<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 2.0.10">
<title>Web on Reactive Stack</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | https://asciidoctor.org */
/* Uncomment @import statement to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}
audio,video{display:inline-block}
audio:not([controls]){display:none;height:0}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:none}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:0}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt{background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
:not(pre):not([class^=L])>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
:not(pre)>code.nobreak{word-wrap:normal}
:not(pre)>code.nowrap{white-space:nowrap}
pre{color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;line-height:1.45;text-rendering:optimizeSpeed}
pre code,pre pre{color:inherit;font-size:inherit;line-height:inherit}
pre>code{display:block}
pre.nowrap,pre.nowrap pre{white-space:pre;word-wrap:normal}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
details,.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
details>summary:first-of-type{cursor:pointer;display:list-item;outline:none;margin-bottom:.75em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#dbdbd6;margin-bottom:1.25em;padding:1.25em;background:#f3f3f2;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock>.content>pre{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.listingblock>.content>pre{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.listingblock>.content>pre{font-size:1em}}
.literalblock pre,.listingblock>.content>pre:not(.highlight),.listingblock>.content>pre[class="highlight"],.listingblock>.content>pre[class^="highlight "]{background:#f7f7f8}
.literalblock.output pre{color:#f7f7f8;background:rgba(0,0,0,.9)}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:inherit;opacity:.5}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:inherit;opacity:.5}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.prettyprint{background:#f7f7f8}
pre.prettyprint .linenums{line-height:1.45;margin-left:2em}
pre.prettyprint li{background:none;list-style-type:inherit;padding-left:0}
pre.prettyprint li code[data-lang]::before{opacity:1}
pre.prettyprint li:not(:first-child) code[data-lang]::before{display:none}
table.linenotable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.linenotable td[class]{color:inherit;vertical-align:top;padding:0;line-height:inherit;white-space:normal}
table.linenotable td.code{padding-left:.75em}
table.linenotable td.linenos{border-right:1px solid currentColor;opacity:.35;padding-right:.5em}
pre.pygments .lineno{border-right:1px solid currentColor;opacity:.35;display:inline-block;margin-right:.75em}
pre.pygments .lineno::before{content:"";margin-right:-.125em}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock:not(.excerpt)>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt>blockquote,.quoteblock .quoteblock{padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt,.quoteblock .quoteblock{margin-left:0}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock{max-width:100%;border-collapse:separate}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content>:last-child{margin-bottom:-1.25em}
td.tableblock>.content>:last-child.sidebarblock{margin-bottom:0}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd),table.stripes-even tr:nth-of-type(even),table.stripes-hover tr:hover{background:#f8f8f7}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background:#00fafa}
.black{color:#000}
.black-background{background:#000}
.blue{color:#0000bf}
.blue-background{background:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background:#fa00fa}
.gray{color:#606060}
.gray-background{background:#7d7d7d}
.green{color:#006000}
.green-background{background:#007d00}
.lime{color:#00bf00}
.lime-background{background:#00fa00}
.maroon{color:#600000}
.maroon-background{background:#7d0000}
.navy{color:#000060}
.navy-background{background:#00007d}
.olive{color:#606000}
.olive-background{background:#7d7d00}
.purple{color:#600060}
.purple-background{background:#7d007d}
.red{color:#bf0000}
.red-background{background:#fa0000}
.silver{color:#909090}
.silver-background{background:#bcbcbc}
.teal{color:#006060}
.teal-background{background:#007d7d}
.white{color:#bfbfbf}
.white-background{background:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!-- Generate a nice TOC -->
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery.tocify/1.9.0/javascripts/jquery.tocify.min.js"></script>
<!-- We do not need the tocify CSS because the asciidoc CSS already provides most of what we neeed -->

<style>
    .tocify-header {
        font-style: italic;
    }

    .tocify-subheader {
        font-style: normal;
        font-size: 90%;
    }

    .tocify ul {
        margin: 0;
    }

    .tocify-focus {
        color: #faa94c;
    }

    .tocify-focus > a {
        color: #faa94c;
    }
</style>

<script type="text/javascript">
    $(function () {
        // Add a new container for the tocify toc into the existing toc so we can re-use its
        // styling
        $("#toc").append("<div id='generated-toc'></div>");
        $("#generated-toc").tocify({
            extendPage: true,
            context: "#content",
            highlightOnScroll: true,
            hideEffect: "slideUp",
            // Use the IDs that asciidoc already provides so that TOC links and intra-document
            // links are the same. Anything else might confuse users when they create bookmarks.
            hashGenerator: function(text, element) {
                return $(element).attr("id");
            },
            // Smooth scrolling doesn't work properly if we use the asciidoc IDs
            smoothScroll: false,
            // Set to 'none' to use the tocify classes
            theme: "none",
            // Handle book (may contain h1) and article (only h2 deeper)
            selectors: $( "#content" ).has( "h1" ).size() > 0 ? "h1,h2,h3,h4,h5" : "h2,h3,h4,h5",
            ignoreSelector: ".discrete"
        });

        // Switch between static asciidoc toc and dynamic tocify toc based on browser size
        // This is set to match the media selectors in the asciidoc CSS
        // Without this, we keep the dynamic toc even if it is moved from the side to preamble
        // position which will cause odd scrolling behavior
        var handleTocOnResize = function() {
            if ($(document).width() < 768) {
                $("#generated-toc").hide();
                $(".sectlevel0").show();
                $(".sectlevel1").show();
            }
            else {
                $("#generated-toc").show();
                $(".sectlevel0").hide();
                $(".sectlevel1").hide();
            }
        }

        $(window).resize(handleTocOnResize);
        handleTocOnResize();
    });
</script>
</head>
<body id="spring-web-reactive" class="article toc2 toc-left">
<div id="header">
<h1>Web on Reactive Stack</h1>
<div id="toc" class="toc2">
<div id="toctitle">目录</div>
<ul class="sectlevel1">
<li><a href="#webflux">1. Spring WebFlux</a>
<ul class="sectlevel2">
<li><a href="#webflux-new-framework">1.1. Overview</a>
<ul class="sectlevel3">
<li><a href="#webflux-why-reactive">1.1.1. Define &#8220;Reactive&#8221;</a></li>
<li><a href="#webflux-reactive-api">1.1.2. Reactive API</a></li>
<li><a href="#webflux-programming-models">1.1.3. Programming Models</a></li>
<li><a href="#webflux-framework-choice">1.1.4. Applicability</a></li>
<li><a href="#webflux-server-choice">1.1.5. Servers</a></li>
<li><a href="#webflux-performance">1.1.6. Performance</a></li>
<li><a href="#webflux-concurrency-model">1.1.7. Concurrency Model</a></li>
</ul>
</li>
<li><a href="#webflux-reactive-spring-web">1.2. Reactive Core</a>
<ul class="sectlevel3">
<li><a href="#webflux-httphandler">1.2.1. <code>HttpHandler</code></a></li>
<li><a href="#webflux-web-handler-api">1.2.2. <code>WebHandler</code> API</a>
<ul class="sectlevel4">
<li><a href="#webflux-web-handler-api-special-beans">Special bean types</a></li>
<li><a href="#webflux-form-data">Form Data</a></li>
<li><a href="#webflux-multipart">Multipart Data</a></li>
<li><a href="#webflux-forwarded-headers">Forwarded Headers</a></li>
</ul>
</li>
<li><a href="#webflux-filters">1.2.3. Filters</a>
<ul class="sectlevel4">
<li><a href="#webflux-filters-cors">CORS</a></li>
</ul>
</li>
<li><a href="#webflux-exception-handler">1.2.4. Exceptions</a></li>
<li><a href="#webflux-codecs">1.2.5. Codecs</a>
<ul class="sectlevel4">
<li><a href="#webflux-codecs-jackson">Jackson JSON</a></li>
<li><a href="#webflux-codecs-forms">Form Data</a></li>
<li><a href="#webflux-codecs-multipart">Multipart</a></li>
<li><a href="#webflux-codecs-limits">Limits</a></li>
<li><a href="#webflux-codecs-streaming">Streaming</a></li>
<li><a href="#webflux-codecs-buffers"><code>DataBuffer</code></a></li>
</ul>
</li>
<li><a href="#webflux-logging">1.2.6. Logging</a>
<ul class="sectlevel4">
<li><a href="#webflux-logging-id">Log Id</a></li>
<li><a href="#webflux-logging-sensitive-data">Sensitive Data</a></li>
<li><a href="#webflux-logging-appenders">Appenders</a></li>
<li><a href="#webflux-codecs-custom">Custom codecs</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#webflux-dispatcher-handler">1.3. <code>DispatcherHandler</code></a>
<ul class="sectlevel3">
<li><a href="#webflux-special-bean-types">1.3.1. Special Bean Types</a></li>
<li><a href="#webflux-framework-config">1.3.2. WebFlux Config</a></li>
<li><a href="#webflux-dispatcher-handler-sequence">1.3.3. Processing</a></li>
<li><a href="#webflux-resulthandling">1.3.4. Result Handling</a></li>
<li><a href="#webflux-dispatcher-exceptions">1.3.5. Exceptions</a></li>
<li><a href="#webflux-viewresolution">1.3.6. View Resolution</a>
<ul class="sectlevel4">
<li><a href="#webflux-viewresolution-handling">Handling</a></li>
<li><a href="#webflux-redirecting-redirect-prefix">Redirecting</a></li>
<li><a href="#webflux-multiple-representations">Content Negotiation</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#webflux-controller">1.4. Annotated Controllers</a>
<ul class="sectlevel3">
<li><a href="#webflux-ann-controller">1.4.1. <code>@Controller</code></a></li>
<li><a href="#webflux-ann-requestmapping">1.4.2. Request Mapping</a>
<ul class="sectlevel4">
<li><a href="#webflux-ann-requestmapping-uri-templates">URI Patterns</a></li>
<li><a href="#webflux-ann-requestmapping-pattern-comparison">Pattern Comparison</a></li>
<li><a href="#webflux-ann-requestmapping-consumes">Consumable Media Types</a></li>
<li><a href="#webflux-ann-requestmapping-produces">Producible Media Types</a></li>
<li><a href="#webflux-ann-requestmapping-params-and-headers">Parameters and Headers</a></li>
<li><a href="#webflux-ann-requestmapping-head-options">HTTP HEAD, OPTIONS</a></li>
<li><a href="#webflux-ann-requestmapping-composed">Custom Annotations</a></li>
<li><a href="#webflux-ann-requestmapping-registration">Explicit Registrations</a></li>
</ul>
</li>
<li><a href="#webflux-ann-methods">1.4.3. Handler Methods</a>
<ul class="sectlevel4">
<li><a href="#webflux-ann-arguments">Method Arguments</a></li>
<li><a href="#webflux-ann-return-types">Return Values</a></li>
<li><a href="#webflux-ann-typeconversion">Type Conversion</a></li>
<li><a href="#webflux-ann-matrix-variables">Matrix Variables</a></li>
<li><a href="#webflux-ann-requestparam"><code>@RequestParam</code></a></li>
<li><a href="#webflux-ann-requestheader"><code>@RequestHeader</code></a></li>
<li><a href="#webflux-ann-cookievalue"><code>@CookieValue</code></a></li>
<li><a href="#webflux-ann-modelattrib-method-args"><code>@ModelAttribute</code></a></li>
<li><a href="#webflux-ann-sessionattributes"><code>@SessionAttributes</code></a></li>
<li><a href="#webflux-ann-sessionattribute"><code>@SessionAttribute</code></a></li>
<li><a href="#webflux-ann-requestattrib"><code>@RequestAttribute</code></a></li>
<li><a href="#webflux-multipart-forms">Multipart Content</a></li>
<li><a href="#webflux-ann-requestbody"><code>@RequestBody</code></a></li>
<li><a href="#webflux-ann-httpentity"><code>HttpEntity</code></a></li>
<li><a href="#webflux-ann-responsebody"><code>@ResponseBody</code></a></li>
<li><a href="#webflux-ann-responseentity"><code>ResponseEntity</code></a></li>
<li><a href="#webflux-ann-jackson">Jackson JSON</a></li>
</ul>
</li>
<li><a href="#webflux-ann-modelattrib-methods">1.4.4. <code>Model</code></a></li>
<li><a href="#webflux-ann-initbinder">1.4.5. <code>DataBinder</code></a></li>
<li><a href="#webflux-ann-controller-exceptions">1.4.6. Managing Exceptions</a>
<ul class="sectlevel4">
<li><a href="#webflux-ann-rest-exceptions">REST API exceptions</a></li>
</ul>
</li>
<li><a href="#webflux-ann-controller-advice">1.4.7. Controller Advice</a></li>
</ul>
</li>
<li><a href="#webflux-fn">1.5. Functional Endpoints</a>
<ul class="sectlevel3">
<li><a href="#webflux-fn-overview">1.5.1. Overview</a></li>
<li><a href="#webflux-fn-handler-functions">1.5.2. HandlerFunction</a>
<ul class="sectlevel4">
<li><a href="#webflux-fn-request">ServerRequest</a></li>
<li><a href="#webflux-fn-response">ServerResponse</a></li>
<li><a href="#webflux-fn-handler-classes">Handler Classes</a></li>
<li><a href="#webflux-fn-handler-validation">Validation</a></li>
</ul>
</li>
<li><a href="#webflux-fn-router-functions">1.5.3. <code>RouterFunction</code></a>
<ul class="sectlevel4">
<li><a href="#webflux-fn-predicates">Predicates</a></li>
<li><a href="#webflux-fn-routes">Routes</a></li>
<li><a href="#_nested_routes">Nested Routes</a></li>
</ul>
</li>
<li><a href="#webflux-fn-running">1.5.4. Running a Server</a></li>
<li><a href="#webflux-fn-handler-filter-function">1.5.5. Filtering Handler Functions</a></li>
</ul>
</li>
<li><a href="#webflux-uri-building">1.6. URI Links</a>
<ul class="sectlevel3">
<li><a href="#web-uricomponents">1.6.1. UriComponents</a></li>
<li><a href="#web-uribuilder">1.6.2. UriBuilder</a></li>
<li><a href="#web-uri-encoding">1.6.3. URI Encoding</a></li>
</ul>
</li>
<li><a href="#webflux-cors">1.7. CORS</a>
<ul class="sectlevel3">
<li><a href="#webflux-cors-intro">1.7.1. Introduction</a></li>
<li><a href="#webflux-cors-processing">1.7.2. Processing</a></li>
<li><a href="#webflux-cors-controller">1.7.3. <code>@CrossOrigin</code></a></li>
<li><a href="#webflux-cors-global">1.7.4. Global Configuration</a></li>
<li><a href="#webflux-cors-webfilter">1.7.5. CORS <code>WebFilter</code></a></li>
</ul>
</li>
<li><a href="#webflux-web-security">1.8. Web Security</a></li>
<li><a href="#webflux-view">1.9. View Technologies</a>
<ul class="sectlevel3">
<li><a href="#webflux-view-thymeleaf">1.9.1. Thymeleaf</a></li>
<li><a href="#webflux-view-freemarker">1.9.2. FreeMarker</a>
<ul class="sectlevel4">
<li><a href="#webflux-view-freemarker-contextconfig">View Configuration</a></li>
<li><a href="#webflux-views-freemarker">FreeMarker Configuration</a></li>
<li><a href="#webflux-view-freemarker-forms">Form Handling</a></li>
</ul>
</li>
<li><a href="#webflux-view-script">1.9.3. Script Views</a>
<ul class="sectlevel4">
<li><a href="#webflux-view-script-dependencies">Requirements</a></li>
<li><a href="#webflux-view-script-integrate">Script Templates</a></li>
</ul>
</li>
<li><a href="#webflux-view-httpmessagewriter">1.9.4. JSON and XML</a></li>
</ul>
</li>
<li><a href="#webflux-caching">1.10. HTTP Caching</a>
<ul class="sectlevel3">
<li><a href="#webflux-caching-cachecontrol">1.10.1. <code>CacheControl</code></a></li>
<li><a href="#webflux-caching-etag-lastmodified">1.10.2. Controllers</a></li>
<li><a href="#webflux-caching-static-resources">1.10.3. Static Resources</a></li>
</ul>
</li>
<li><a href="#webflux-config">1.11. WebFlux Config</a>
<ul class="sectlevel3">
<li><a href="#webflux-config-enable">1.11.1. Enabling WebFlux Config</a></li>
<li><a href="#webflux-config-customize">1.11.2. WebFlux config API</a></li>
<li><a href="#webflux-config-conversion">1.11.3. Conversion, formatting</a></li>
<li><a href="#webflux-config-validation">1.11.4. Validation</a></li>
<li><a href="#webflux-config-content-negotiation">1.11.5. Content Type Resolvers</a></li>
<li><a href="#webflux-config-message-codecs">1.11.6. HTTP message codecs</a></li>
<li><a href="#webflux-config-view-resolvers">1.11.7. View Resolvers</a></li>
<li><a href="#webflux-config-static-resources">1.11.8. Static Resources</a></li>
<li><a href="#webflux-config-path-matching">1.11.9. Path Matching</a></li>
<li><a href="#webflux-config-websocket-service">1.11.10. WebSocketService</a></li>
<li><a href="#webflux-config-advanced-java">1.11.11. Advanced Configuration Mode</a></li>
</ul>
</li>
<li><a href="#webflux-http2">1.12. HTTP/2</a></li>
</ul>
</li>
<li><a href="#webflux-client">2. WebClient</a>
<ul class="sectlevel2">
<li><a href="#webflux-client-builder">2.1. Configuration</a>
<ul class="sectlevel3">
<li><a href="#webflux-client-builder-maxinmemorysize">2.1.1. MaxInMemorySize</a></li>
<li><a href="#webflux-client-builder-reactor">2.1.2. Reactor Netty</a>
<ul class="sectlevel4">
<li><a href="#webflux-client-builder-reactor-resources">Resources</a></li>
<li><a href="#webflux-client-builder-reactor-timeout">Timeouts</a></li>
</ul>
</li>
<li><a href="#webflux-client-builder-jetty">2.1.3. Jetty</a></li>
<li><a href="#webflux-client-builder-http-components">2.1.4. HttpComponents</a></li>
</ul>
</li>
<li><a href="#webflux-client-retrieve">2.2. <code>retrieve()</code></a></li>
<li><a href="#webflux-client-exchange">2.3. Exchange</a></li>
<li><a href="#webflux-client-body">2.4. Request Body</a>
<ul class="sectlevel3">
<li><a href="#webflux-client-body-form">2.4.1. Form Data</a></li>
<li><a href="#webflux-client-body-multipart">2.4.2. Multipart Data</a></li>
</ul>
</li>
<li><a href="#webflux-client-filter">2.5. Filters</a></li>
<li><a href="#webflux-client-attributes">2.6. Attributes</a></li>
<li><a href="#webflux-client-context">2.7. Context</a></li>
<li><a href="#webflux-client-synchronous">2.8. Synchronous Use</a></li>
<li><a href="#webflux-client-testing">2.9. Testing</a></li>
</ul>
</li>
<li><a href="#webflux-websocket">3. WebSockets</a>
<ul class="sectlevel2">
<li><a href="#websocket-intro">3.1. Introduction to WebSocket</a>
<ul class="sectlevel3">
<li><a href="#websocket-intro-architecture">3.1.1. HTTP Versus WebSocket</a></li>
<li><a href="#websocket-intro-when-to-use">3.1.2. When to Use WebSockets</a></li>
</ul>
</li>
<li><a href="#webflux-websocket-server">3.2. WebSocket API</a>
<ul class="sectlevel3">
<li><a href="#webflux-websocket-server-handler">3.2.1. Server</a></li>
<li><a href="#webflux-websockethandler">3.2.2. <code>WebSocketHandler</code></a></li>
<li><a href="#webflux-websocket-databuffer">3.2.3. <code>DataBuffer</code></a></li>
<li><a href="#webflux-websocket-server-handshake">3.2.4. Handshake</a></li>
<li><a href="#webflux-websocket-server-config">3.2.5. Server Configation</a></li>
<li><a href="#webflux-websocket-server-cors">3.2.6. CORS</a></li>
<li><a href="#webflux-websocket-client">3.2.7. Client</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#webflux-test">4. Testing</a></li>
<li><a href="#rsocket">5. RSocket</a>
<ul class="sectlevel2">
<li><a href="#rsocket-overview">5.1. Overview</a>
<ul class="sectlevel3">
<li><a href="#rsocket-protocol">5.1.1. The Protocol</a></li>
<li><a href="#rsocket-java">5.1.2. Java Implementation</a></li>
<li><a href="#rsocket-spring">5.1.3. Spring Support</a></li>
</ul>
</li>
<li><a href="#rsocket-requester">5.2. RSocketRequester</a>
<ul class="sectlevel3">
<li><a href="#rsocket-requester-client">5.2.1. Client Requester</a>
<ul class="sectlevel4">
<li><a href="#rsocket-requester-client-setup">Connection Setup</a></li>
<li><a href="#rsocket-requester-client-strategies">Strategies</a></li>
<li><a href="#rsocket-requester-client-responder">Client Responders</a></li>
<li><a href="#rsocket-requester-client-advanced">Advanced</a></li>
</ul>
</li>
<li><a href="#rsocket-requester-server">5.2.2. Server Requester</a></li>
<li><a href="#rsocket-requester-requests">5.2.3. Requests</a></li>
</ul>
</li>
<li><a href="#rsocket-annot-responders">5.3. Annotated Responders</a>
<ul class="sectlevel3">
<li><a href="#rsocket-annot-responders-server">5.3.1. Server Responders</a></li>
<li><a href="#rsocket-annot-responders-client">5.3.2. Client Responders</a></li>
<li><a href="#rsocket-annot-messagemapping">5.3.3. @MessageMapping</a></li>
<li><a href="#rsocket-annot-connectmapping">5.3.4. @ConnectMapping</a></li>
</ul>
</li>
<li><a href="#rsocket-metadata-extractor">5.4. MetadataExtractor</a></li>
</ul>
</li>
<li><a href="#webflux-reactive-libraries">6. Reactive Libraries</a></li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Version 5.3.3
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>This part of the documentation covers support for reactive-stack web applications built
on a <a href="https://www.reactive-streams.org/">Reactive Streams</a> API to run on non-blocking
servers, such as Netty, Undertow, and Servlet 3.1+ containers. Individual chapters cover
the <a href="webflux.html#webflux">Spring WebFlux</a> framework,
the reactive <a href="#webflux-client"><code>WebClient</code></a>, support for <a href="#webflux-test">testing</a>,
and <a href="#webflux-reactive-libraries">reactive libraries</a>. For Servlet-stack web applications,
see <a href="web.html#spring-web">Web on Servlet Stack</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="webflux">1. Spring WebFlux</h2>
<div class="sectionbody">
<div class="paragraph">
<p>The original web framework included in the Spring Framework, Spring Web MVC, was
purpose-built for the Servlet API and Servlet containers. The reactive-stack web framework,
Spring WebFlux, was added later in version 5.0. It is fully non-blocking, supports
<a href="https://www.reactive-streams.org/">Reactive Streams</a> back pressure, and runs on such servers as
Netty, Undertow, and Servlet 3.1+ containers.</p>
</div>
<div class="paragraph">
<p>Both web frameworks mirror the names of their source modules
(<a href="https://github.com/spring-projects/spring-framework/tree/master/spring-webmvc">spring-webmvc</a> and
<a href="https://github.com/spring-projects/spring-framework/tree/master/spring-webflux">spring-webflux</a>)
and co-exist side by side in the Spring Framework. Each module is optional.
Applications can use one or the other module or, in some cases, both&#8201;&#8212;&#8201;for example, Spring MVC controllers with the reactive <code>WebClient</code>.</p>
</div>
<div class="sect2">
<h3 id="webflux-new-framework">1.1. Overview</h3>
<div class="paragraph">
<p>Why was Spring WebFlux created?</p>
</div>
<div class="paragraph">
<p>Part of the answer is the need for a non-blocking web stack to handle concurrency with a
small number of threads and scale with fewer hardware resources. Servlet 3.1 did provide
an API for non-blocking I/O. However, using it leads away from the rest of the Servlet API,
where contracts are synchronous (<code>Filter</code>, <code>Servlet</code>) or blocking (<code>getParameter</code>,
<code>getPart</code>). This was the motivation for a new common API to serve as a foundation across
any non-blocking runtime. That is important because of servers (such as Netty) that are
well-established in the async, non-blocking space.</p>
</div>
<div class="paragraph">
<p>The other part of the answer is functional programming. Much as the addition of annotations
in Java 5 created opportunities (such as annotated REST controllers or unit tests), the addition
of lambda expressions in Java 8 created opportunities for functional APIs in Java.
This is a boon for non-blocking applications and continuation-style APIs (as popularized
by <code>CompletableFuture</code> and <a href="http://reactivex.io/">ReactiveX</a>) that allow declarative
composition of asynchronous logic. At the programming-model level, Java 8 enabled Spring
WebFlux to offer functional web endpoints alongside annotated controllers.</p>
</div>
<div class="sect3">
<h4 id="webflux-why-reactive">1.1.1. Define &#8220;Reactive&#8221;</h4>
<div class="paragraph">
<p>We touched on &#8220;non-blocking&#8221; and &#8220;functional&#8221; but what does reactive mean?</p>
</div>
<div class="paragraph">
<p>The term, &#8220;reactive,&#8221; refers to programming models that are built around reacting to change&#8201;&#8212;&#8201;network components reacting to I/O events, UI controllers reacting to mouse events, and others.
In that sense, non-blocking is reactive, because, instead of being blocked, we are now in the mode
of reacting to notifications as operations complete or data becomes available.</p>
</div>
<div class="paragraph">
<p>There is also another important mechanism that we on the Spring team associate with &#8220;reactive&#8221;
and that is non-blocking back pressure. In synchronous, imperative code, blocking calls
serve as a natural form of back pressure that forces the caller to wait. In non-blocking
code, it becomes important to control the rate of events so that a fast producer does not
overwhelm its destination.</p>
</div>
<div class="paragraph">
<p>Reactive Streams is a
<a href="https://github.com/reactive-streams/reactive-streams-jvm/blob/master/README.md#specification">small spec</a>
(also <a href="https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Flow.html">adopted</a> in Java 9)
that defines the interaction between asynchronous components with back pressure.
For example a data repository (acting as
<a href="https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/org/reactivestreams/Publisher.html">Publisher</a>)
can produce data that an HTTP server (acting as
<a href="https://www.reactive-streams.org/reactive-streams-1.0.1-javadoc/org/reactivestreams/Subscriber.html">Subscriber</a>)
can then write to the response. The main purpose of Reactive Streams is to let the
  subscriber control how quickly or how slowly the publisher produces data.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<strong>Common question: what if a publisher cannot slow down?</strong><br>
The purpose of Reactive Streams is only to establish the mechanism and a boundary.
If a publisher cannot slow down, it has to decide whether to buffer, drop, or fail.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-reactive-api">1.1.2. Reactive API</h4>
<div class="paragraph">
<p>Reactive Streams plays an important role for interoperability. It is of interest to libraries
and infrastructure components but less useful as an application API, because it is too
low-level. Applications need a higher-level and richer, functional API to
compose async logic&#8201;&#8212;&#8201;similar to the Java 8 <code>Stream</code> API but not only for collections.
This is the role that reactive libraries play.</p>
</div>
<div class="paragraph">
<p><a href="https://github.com/reactor/reactor">Reactor</a> is the reactive library of choice for
Spring WebFlux. It provides the
<a href="https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html"><code>Mono</code></a> and
<a href="https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html"><code>Flux</code></a> API types
to work on data sequences of 0..1 (<code>Mono</code>) and 0..N (<code>Flux</code>) through a rich set of operators aligned with the
ReactiveX <a href="http://reactivex.io/documentation/operators.html">vocabulary of operators</a>.
Reactor is a Reactive Streams library and, therefore, all of its operators support non-blocking back pressure.
Reactor has a strong focus on server-side Java. It is developed in close collaboration
with Spring.</p>
</div>
<div class="paragraph">
<p>WebFlux requires Reactor as a core dependency but it is interoperable with other reactive
libraries via Reactive Streams. As a general rule, a WebFlux API accepts a plain <code>Publisher</code>
as input, adapts it to a Reactor type internally, uses that, and returns either a
<code>Flux</code> or a <code>Mono</code> as output. So, you can pass any <code>Publisher</code> as input and you can apply
operations on the output, but you need to adapt the output for use with another reactive library.
Whenever feasible (for example, annotated controllers), WebFlux adapts transparently to the use
of RxJava or another reactive library. See <a href="#webflux-reactive-libraries">Reactive Libraries</a> for more details.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
In addition to Reactive APIs, WebFlux can also be used with
<a href="languages.html#coroutines">Coroutines</a> APIs in Kotlin which provides a more imperative style of programming.
The following Kotlin code samples will be provided with Coroutines APIs.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-programming-models">1.1.3. Programming Models</h4>
<div class="paragraph">
<p>The <code>spring-web</code> module contains the reactive foundation that underlies Spring WebFlux,
including HTTP abstractions, Reactive Streams <a href="#webflux-httphandler">adapters</a> for supported
servers, <a href="#webflux-codecs">codecs</a>, and a core <a href="#webflux-web-handler-api"><code>WebHandler</code> API</a> comparable to
the Servlet API but with non-blocking contracts.</p>
</div>
<div class="paragraph">
<p>On that foundation, Spring WebFlux provides a choice of two programming models:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#webflux-controller">Annotated Controllers</a>: Consistent with Spring MVC and based on the same annotations
from the <code>spring-web</code> module. Both Spring MVC and WebFlux controllers support reactive
(Reactor and RxJava) return types, and, as a result, it is not easy to tell them apart. One notable
difference is that WebFlux also supports reactive <code>@RequestBody</code> arguments.</p>
</li>
<li>
<p><a href="#webflux-fn">Functional Endpoints</a>: Lambda-based, lightweight, and functional programming model. You can think of
this as a small library or a set of utilities that an application can use to route and
handle requests. The big difference with annotated controllers is that the application
is in charge of request handling from start to finish versus declaring intent through
annotations and being called back.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="webflux-framework-choice">1.1.4. Applicability</h4>
<div class="paragraph">
<p>Spring MVC or WebFlux?</p>
</div>
<div class="paragraph">
<p>A natural question to ask but one that sets up an unsound dichotomy. Actually, both
work together to expand the range of available options. The two are designed for
continuity and consistency with each other, they are available side by side, and feedback
from each side benefits both sides. The following diagram shows how the two relate, what they
have in common, and what each supports uniquely:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="images/spring-mvc-and-webflux-venn.png" alt="spring mvc and webflux venn">
</div>
</div>
<div class="paragraph">
<p>We suggest that you consider the following specific points:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>If you have a Spring MVC application that works fine, there is no need to change.
Imperative programming is the easiest way to write, understand, and debug code.
You have maximum choice of libraries, since, historically, most are blocking.</p>
</li>
<li>
<p>If you are already shopping for a non-blocking web stack, Spring WebFlux offers the same
execution model benefits as others in this space and also provides a choice of servers
(Netty, Tomcat, Jetty, Undertow, and Servlet 3.1+ containers), a choice of programming models
(annotated controllers and functional web endpoints), and a choice of reactive libraries
(Reactor, RxJava, or other).</p>
</li>
<li>
<p>If you are interested in a lightweight, functional web framework for use with Java 8 lambdas
or Kotlin, you can use the Spring WebFlux functional web endpoints. That can also be a good choice
for smaller applications or microservices with less complex requirements that can benefit
from greater transparency and control.</p>
</li>
<li>
<p>In a microservice architecture, you can have a mix of applications with either Spring MVC
or Spring WebFlux controllers or with Spring WebFlux functional endpoints. Having support
for the same annotation-based programming model in both frameworks makes it easier to
re-use knowledge while also selecting the right tool for the right job.</p>
</li>
<li>
<p>A simple way to evaluate an application is to check its dependencies. If you have blocking
persistence APIs (JPA, JDBC) or networking APIs to use, Spring MVC is the best choice
for common architectures at least. It is technically feasible with both Reactor and
RxJava to perform blocking calls on a separate thread but you would not be making the
most of a non-blocking web stack.</p>
</li>
<li>
<p>If you have a Spring MVC application with calls to remote services, try the reactive <code>WebClient</code>.
You can return reactive types (Reactor, RxJava, <a href="#webflux-reactive-libraries">or other</a>)
directly from Spring MVC controller methods. The greater the latency per call or the
interdependency among calls, the more dramatic the benefits. Spring MVC controllers
can call other reactive components too.</p>
</li>
<li>
<p>If you have a large team, keep in mind the steep learning curve in the shift to non-blocking,
functional, and declarative programming. A practical way to start without a full switch
is to use the reactive <code>WebClient</code>. Beyond that, start small and measure the benefits.
We expect that, for a wide range of applications, the shift is unnecessary. If you are
unsure what benefits to look for, start by learning about how non-blocking I/O works
(for example, concurrency on single-threaded Node.js) and its effects.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="webflux-server-choice">1.1.5. Servers</h4>
<div class="paragraph">
<p>Spring WebFlux is supported on Tomcat, Jetty, Servlet 3.1+ containers, as well as on
non-Servlet runtimes such as Netty and Undertow. All servers are adapted to a low-level,
<a href="#webflux-httphandler">common API</a> so that higher-level
<a href="#webflux-programming-models">programming models</a> can be supported across servers.</p>
</div>
<div class="paragraph">
<p>Spring WebFlux does not have built-in support to start or stop a server. However, it is
easy to <a href="#webflux-web-handler-api">assemble</a> an application from Spring configuration and
<a href="#webflux-config">WebFlux infrastructure</a> and <a href="#webflux-httphandler">run it</a> with a few
lines of code.</p>
</div>
<div class="paragraph">
<p>Spring Boot has a WebFlux starter that automates these steps. By default, the starter uses
Netty, but it is easy to switch to Tomcat, Jetty, or Undertow by changing your
Maven or Gradle dependencies. Spring Boot defaults to Netty, because it is more widely
used in the asynchronous, non-blocking space and lets a client and a server share resources.</p>
</div>
<div class="paragraph">
<p>Tomcat and Jetty can be used with both Spring MVC and WebFlux. Keep in mind, however, that
the way they are used is very different. Spring MVC relies on Servlet blocking I/O and
lets applications use the Servlet API directly if they need to. Spring WebFlux
relies on Servlet 3.1 non-blocking I/O and uses the Servlet API behind a low-level
adapter. It is not exposed for direct use.</p>
</div>
<div class="paragraph">
<p>For Undertow, Spring WebFlux uses Undertow APIs directly without the Servlet API.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-performance">1.1.6. Performance</h4>
<div class="paragraph">
<p>Performance has many characteristics and meanings. Reactive and non-blocking generally
do not make applications run faster. They can, in some cases, (for example, if using the
<code>WebClient</code> to run remote calls in parallel). On the whole, it requires more work to do
things the non-blocking way and that can slightly increase the required processing time.</p>
</div>
<div class="paragraph">
<p>The key expected benefit of reactive and non-blocking is the ability to scale with a small,
fixed number of threads and less memory. That makes applications more resilient under load,
because they scale in a more predictable way. In order to observe those benefits, however, you
need to have some latency (including a mix of slow and unpredictable network I/O).
That is where the reactive stack begins to show its strengths, and the differences can be
dramatic.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-concurrency-model">1.1.7. Concurrency Model</h4>
<div class="paragraph">
<p>Both Spring MVC and Spring WebFlux support annotated controllers, but there is a key
difference in the concurrency model and the default assumptions for blocking and threads.</p>
</div>
<div class="paragraph">
<p>In Spring MVC (and servlet applications in general), it is assumed that applications can
block the current thread, (for example, for remote calls). For this reason, servlet containers
use a large thread pool to absorb potential blocking during request handling.</p>
</div>
<div class="paragraph">
<p>In Spring WebFlux (and non-blocking servers in general), it is assumed that applications
do not block. Therefore, non-blocking servers use  a small, fixed-size thread pool
(event loop workers) to handle requests.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
&#8220;To scale&#8221; and &#8220;small number of threads&#8221; may sound contradictory but to never block the
current thread (and rely on callbacks instead) means that you do not need extra threads, as
there are no blocking calls to absorb.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<div class="title">Invoking a Blocking API</div>
<p>What if you do need to use a blocking library? Both Reactor and RxJava provide the
<code>publishOn</code> operator to continue processing on a different thread. That means there is an
easy escape hatch. Keep in mind, however, that blocking APIs are not a good fit for
this concurrency model.</p>
</div>
<div class="paragraph">
<div class="title">Mutable State</div>
<p>In Reactor and RxJava, you declare logic through operators. At runtime, a reactive
pipeline is formed where data is processed sequentially, in distinct stages. A key benefit
of this is that it frees applications from having to protect mutable state because
application code within that pipeline is never invoked concurrently.</p>
</div>
<div class="paragraph">
<div class="title">Threading Model</div>
<p>What threads should you expect to see on a server running with Spring WebFlux?</p>
</div>
<div class="ulist">
<ul>
<li>
<p>On a &#8220;vanilla&#8221; Spring WebFlux server (for example, no data access nor other optional
dependencies), you can expect one thread for the server and several others for request
processing (typically as many as the number of CPU cores). Servlet containers, however,
may start with more threads (for example, 10 on Tomcat), in support of both servlet (blocking) I/O
and servlet 3.1 (non-blocking) I/O usage.</p>
</li>
<li>
<p>The reactive <code>WebClient</code> operates in event loop style. So you can see a small, fixed
number of processing threads related to that (for example, <code>reactor-http-nio-</code> with the Reactor
Netty connector). However, if Reactor Netty is used for both client and server, the two
share event loop resources by default.</p>
</li>
<li>
<p>Reactor and RxJava provide thread pool abstractions, called schedulers, to use with the
<code>publishOn</code> operator that is used to switch processing to a different thread pool.
The schedulers have names that suggest a specific concurrency strategy&#8201;&#8212;&#8201;for example, &#8220;parallel&#8221;
(for CPU-bound work with a limited number of threads) or &#8220;elastic&#8221; (for I/O-bound work with
a large number of threads). If you see such threads, it means some code is using a
specific thread pool <code>Scheduler</code> strategy.</p>
</li>
<li>
<p>Data access libraries and other third party dependencies can also create and use threads
of their own.</p>
</li>
</ul>
</div>
<div class="paragraph">
<div class="title">Configuring</div>
<p>The Spring Framework does not provide support for starting and stopping
<a href="#webflux-server-choice">servers</a>. To configure the threading model for a server,
you need to use server-specific configuration APIs, or, if you use Spring Boot,
check the Spring Boot configuration options for each server. You can
<a href="web-reactive.html#webflux-client-builder">configure</a> the <code>WebClient</code> directly.
For all other libraries, see their respective documentation.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-reactive-spring-web">1.2. Reactive Core</h3>
<div class="paragraph">
<p>The <code>spring-web</code> module contains the following foundational support for reactive web
applications:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>For server request processing there are two levels of support.</p>
<div class="ulist">
<ul>
<li>
<p><a href="#webflux-httphandler">HttpHandler</a>: Basic contract for HTTP request handling with
non-blocking I/O and Reactive Streams back pressure, along with adapters for Reactor Netty,
Undertow, Tomcat, Jetty, and any Servlet 3.1+ container.</p>
</li>
<li>
<p><a href="#webflux-web-handler-api"><code>WebHandler</code> API</a>: Slightly higher level, general-purpose web API for
request handling, on top of which concrete programming models such as annotated
controllers and functional endpoints are built.</p>
</li>
</ul>
</div>
</li>
<li>
<p>For the client side, there is a basic <code>ClientHttpConnector</code> contract to perform HTTP
requests with non-blocking I/O and Reactive Streams back pressure, along with adapters for
<a href="https://github.com/reactor/reactor-netty">Reactor Netty</a>, reactive
<a href="https://github.com/jetty-project/jetty-reactive-httpclient">Jetty HttpClient</a>
and <a href="https://hc.apache.org/">Apache HttpComponents</a>.
The higher level <a href="web-reactive.html#webflux-client">WebClient</a> used in applications
builds on this basic contract.</p>
</li>
<li>
<p>For client and server, <a href="#webflux-codecs">codecs</a> for serialization and
deserialization of HTTP request and response content.</p>
</li>
</ul>
</div>
<div class="sect3">
<h4 id="webflux-httphandler">1.2.1. <code>HttpHandler</code></h4>
<div class="paragraph">
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/http/server/reactive/HttpHandler.html">HttpHandler</a>
is a simple contract with a single method to handle a request and a response. It is
intentionally minimal, and its main and only purpose is to be a minimal abstraction
over different HTTP server APIs.</p>
</div>
<div class="paragraph">
<p>The following table describes the supported server APIs:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 40%;">
<col style="width: 40%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Server name</th>
<th class="tableblock halign-left valign-top">Server API used</th>
<th class="tableblock halign-left valign-top">Reactive Streams support</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Netty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Netty API</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/reactor/reactor-netty">Reactor Netty</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Undertow</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Undertow API</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring-web: Undertow to Reactive Streams bridge</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Tomcat</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Servlet 3.1 non-blocking I/O; Tomcat API to read and write ByteBuffers vs byte[]</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Jetty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Servlet 3.1 non-blocking I/O; Jetty API to write ByteBuffers vs byte[]</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Servlet 3.1 container</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Servlet 3.1 non-blocking I/O</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">spring-web: Servlet 3.1 non-blocking I/O to Reactive Streams bridge</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The following table describes server dependencies (also see
<a href="https://github.com/spring-projects/spring-framework/wiki/What%27s-New-in-the-Spring-Framework">supported versions</a>):</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Server name</th>
<th class="tableblock halign-left valign-top">Group id</th>
<th class="tableblock halign-left valign-top">Artifact name</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Reactor Netty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">io.projectreactor.netty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">reactor-netty</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Undertow</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">io.undertow</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">undertow-core</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Tomcat</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">org.apache.tomcat.embed</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">tomcat-embed-core</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Jetty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">org.eclipse.jetty</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">jetty-server, jetty-servlet</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The code snippets below show using the <code>HttpHandler</code> adapters with each server API:</p>
</div>
<div class="paragraph">
<p><strong>Reactor Netty</strong></p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpHandler handler = ...
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(handler);
HttpServer.create().host(host).port(port).handle(adapter).bind().block();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val handler: HttpHandler = ...
val adapter = ReactorHttpHandlerAdapter(handler)
HttpServer.create().host(host).port(port).handle(adapter).bind().block()</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Undertow</strong></p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpHandler handler = ...
UndertowHttpHandlerAdapter adapter = new UndertowHttpHandlerAdapter(handler);
Undertow server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build();
server.start();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val handler: HttpHandler = ...
val adapter = UndertowHttpHandlerAdapter(handler)
val server = Undertow.builder().addHttpListener(port, host).setHandler(adapter).build()
server.start()</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Tomcat</strong></p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpHandler handler = ...
Servlet servlet = new TomcatHttpHandlerAdapter(handler);

Tomcat server = new Tomcat();
File base = new File(System.getProperty("java.io.tmpdir"));
Context rootContext = server.addContext("", base.getAbsolutePath());
Tomcat.addServlet(rootContext, "main", servlet);
rootContext.addServletMappingDecoded("/", "main");
server.setHost(host);
server.setPort(port);
server.start();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val handler: HttpHandler = ...
val servlet = TomcatHttpHandlerAdapter(handler)

val server = Tomcat()
val base = File(System.getProperty("java.io.tmpdir"))
val rootContext = server.addContext("", base.absolutePath)
Tomcat.addServlet(rootContext, "main", servlet)
rootContext.addServletMappingDecoded("/", "main")
server.host = host
server.setPort(port)
server.start()</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Jetty</strong></p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpHandler handler = ...
Servlet servlet = new JettyHttpHandlerAdapter(handler);

Server server = new Server();
ServletContextHandler contextHandler = new ServletContextHandler(server, "");
contextHandler.addServlet(new ServletHolder(servlet), "/");
contextHandler.start();

ServerConnector connector = new ServerConnector(server);
connector.setHost(host);
connector.setPort(port);
server.addConnector(connector);
server.start();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val handler: HttpHandler = ...
val servlet = JettyHttpHandlerAdapter(handler)

val server = Server()
val contextHandler = ServletContextHandler(server, "")
contextHandler.addServlet(ServletHolder(servlet), "/")
contextHandler.start();

val connector = ServerConnector(server)
connector.host = host
connector.port = port
server.addConnector(connector)
server.start()</code></pre>
</div>
</div>
<div class="paragraph">
<p><strong>Servlet 3.1+ Container</strong></p>
</div>
<div class="paragraph">
<p>To deploy as a WAR to any Servlet 3.1+ container, you can extend and include
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/adapter/AbstractReactiveWebInitializer.html"><code>AbstractReactiveWebInitializer</code></a>
in the WAR. That class wraps an <code>HttpHandler</code> with <code>ServletHttpHandlerAdapter</code> and registers
that as a <code>Servlet</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-web-handler-api">1.2.2. <code>WebHandler</code> API</h4>
<div class="paragraph">
<p>The <code>org.springframework.web.server</code> package builds on the <a href="#webflux-httphandler"><code>HttpHandler</code></a> contract
to provide a general-purpose web API for processing requests through a chain of multiple
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/WebExceptionHandler.html"><code>WebExceptionHandler</code></a>, multiple
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/WebFilter.html"><code>WebFilter</code></a>, and a single
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/WebHandler.html"><code>WebHandler</code></a> component. The chain can
be put together with <code>WebHttpHandlerBuilder</code> by simply pointing to a Spring
<code>ApplicationContext</code> where components are
<a href="#webflux-web-handler-api-special-beans">auto-detected</a>, and/or by registering components
with the builder.</p>
</div>
<div class="paragraph">
<p>While <code>HttpHandler</code> has a simple goal to abstract the use of different HTTP servers, the
<code>WebHandler</code> API aims to provide a broader set of features commonly used in web applications
such as:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>User session with attributes.</p>
</li>
<li>
<p>Request attributes.</p>
</li>
<li>
<p>Resolved <code>Locale</code> or <code>Principal</code> for the request.</p>
</li>
<li>
<p>Access to parsed and cached form data.</p>
</li>
<li>
<p>Abstractions for multipart data.</p>
</li>
<li>
<p>and more..</p>
</li>
</ul>
</div>
<div class="sect4">
<h5 id="webflux-web-handler-api-special-beans">Special bean types</h5>
<div class="paragraph">
<p>The table below lists the components that <code>WebHttpHandlerBuilder</code> can auto-detect in a
Spring ApplicationContext, or that can be registered directly with it:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 25%;">
<col style="width: 12.5%;">
<col style="width: 37.5%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Bean name</th>
<th class="tableblock halign-left valign-top">Bean type</th>
<th class="tableblock halign-left valign-top">Count</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;any&gt;</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WebExceptionHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0..N</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Provide handling for exceptions from the chain of <code>WebFilter</code> instances and the target
  <code>WebHandler</code>. For more details, see <a href="#webflux-exception-handler">Exceptions</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">&lt;any&gt;</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WebFilter</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0..N</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Apply interception style logic to before and after the rest of the filter chain and
  the target <code>WebHandler</code>. For more details, see <a href="#webflux-filters">Filters</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>webHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WebHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The handler for the request.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>webSessionManager</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WebSessionManager</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0..1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The manager for <code>WebSession</code> instances exposed through a method on <code>ServerWebExchange</code>.
  <code>DefaultWebSessionManager</code> by default.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>serverCodecConfigurer</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ServerCodecConfigurer</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0..1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to <code>HttpMessageReader</code> instances for parsing form data and multipart data that is then
  exposed through methods on <code>ServerWebExchange</code>. <code>ServerCodecConfigurer.create()</code> by default.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>localeContextResolver</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>LocaleContextResolver</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0..1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The resolver for <code>LocaleContext</code> exposed through a method on <code>ServerWebExchange</code>.
  <code>AcceptHeaderLocaleContextResolver</code> by default.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>forwardedHeaderTransformer</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ForwardedHeaderTransformer</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0..1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For processing forwarded type headers, either by extracting and removing them or by removing them only.
  Not used by default.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect4">
<h5 id="webflux-form-data">Form Data</h5>
<div class="paragraph">
<p><code>ServerWebExchange</code> exposes the following method for accessing form data:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;MultiValueMap&lt;String, String&gt;&gt; getFormData();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="Kotlin">suspend fun getFormData(): MultiValueMap&lt;String, String&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>DefaultServerWebExchange</code> uses the configured <code>HttpMessageReader</code> to parse form data
(<code>application/x-www-form-urlencoded</code>) into a <code>MultiValueMap</code>. By default,
<code>FormHttpMessageReader</code> is configured for use by the <code>ServerCodecConfigurer</code> bean
(see the <a href="#webflux-web-handler-api">Web Handler API</a>).</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-multipart">Multipart Data</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-multipart">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>ServerWebExchange</code> exposes the following method for accessing multipart data:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;MultiValueMap&lt;String, Part&gt;&gt; getMultipartData();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="Kotlin">suspend fun getMultipartData(): MultiValueMap&lt;String, Part&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>DefaultServerWebExchange</code> uses the configured
<code>HttpMessageReader&lt;MultiValueMap&lt;String, Part&gt;&gt;</code> to parse <code>multipart/form-data</code> content
into a <code>MultiValueMap</code>.
By default, this is the <code>DefaultPartHttpMessageReader</code>, which does not have any third-party
dependencies.
Alternatively, the <code>SynchronossPartHttpMessageReader</code> can be used, which is based on the
<a href="https://github.com/synchronoss/nio-multipart">Synchronoss NIO Multipart</a> library.
Both are configured through the <code>ServerCodecConfigurer</code> bean
(see the <a href="#webflux-web-handler-api">Web Handler API</a>).</p>
</div>
<div class="paragraph">
<p>To parse multipart data in streaming fashion, you can use the <code>Flux&lt;Part&gt;</code> returned from an
<code>HttpMessageReader&lt;Part&gt;</code> instead. For example, in an annotated controller, use of
<code>@RequestPart</code> implies <code>Map</code>-like access to individual parts by name and, hence, requires
parsing multipart data in full. By contrast, you can use <code>@RequestBody</code> to decode the
content to <code>Flux&lt;Part&gt;</code> without collecting to a <code>MultiValueMap</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-forwarded-headers">Forwarded Headers</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#filters-forwarded-headers">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>As a request goes through proxies (such as load balancers), the host, port, and
scheme may change. That makes it a challenge, from a client perspective, to create links that point to the correct
host, port, and scheme.</p>
</div>
<div class="paragraph">
<p><a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a> defines the <code>Forwarded</code> HTTP header
that proxies can use to provide information about the original request. There are other
non-standard headers, too, including <code>X-Forwarded-Host</code>, <code>X-Forwarded-Port</code>,
<code>X-Forwarded-Proto</code>, <code>X-Forwarded-Ssl</code>, and <code>X-Forwarded-Prefix</code>.</p>
</div>
<div class="paragraph">
<p><code>ForwardedHeaderTransformer</code> is a component that modifies the host, port, and scheme of
the request, based on forwarded headers, and then removes those headers. If you declare
it as a bean with the name <code>forwardedHeaderTransformer</code>, it will be
<a href="#webflux-web-handler-api-special-beans">detected</a> and used.</p>
</div>
<div class="paragraph">
<p>There are security considerations for forwarded headers, since an application cannot know
if the headers were added by a proxy, as intended, or by a malicious client. This is why
a proxy at the boundary of trust should be configured to remove untrusted forwarded traffic coming
from the outside. You can also configure the <code>ForwardedHeaderTransformer</code> with
<code>removeOnly=true</code>, in which case it removes but does not use the headers.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
In 5.1 <code>ForwardedHeaderFilter</code> was deprecated and superceded by
<code>ForwardedHeaderTransformer</code> so forwarded headers can be processed earlier, before the
exchange is created. If the filter is configured anyway, it is taken out of the list of
filters, and <code>ForwardedHeaderTransformer</code> is used instead.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-filters">1.2.3. Filters</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#filters">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>In the <a href="#webflux-web-handler-api"><code>WebHandler</code> API</a>, you can use a <code>WebFilter</code> to apply interception-style
logic before and after the rest of the processing chain of filters and the target
<code>WebHandler</code>. When using the <a href="#webflux-config">WebFlux Config</a>, registering a <code>WebFilter</code> is as simple
as declaring it as a Spring bean and (optionally) expressing precedence by using <code>@Order</code> on
the bean declaration or by implementing <code>Ordered</code>.</p>
</div>
<div class="sect4">
<h5 id="webflux-filters-cors">CORS</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#filters-cors">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux provides fine-grained support for CORS configuration through annotations on
controllers. However, when you use it with Spring Security, we advise relying on the built-in
<code>CorsFilter</code>, which must be ordered ahead of Spring Security&#8217;s chain of filters.</p>
</div>
<div class="paragraph">
<p>See the section on <a href="#webflux-cors">CORS</a> and the <a href="webflux-cors.html#webflux-cors-webfilter">webflux-cors.html</a> for more details.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-exception-handler">1.2.4. Exceptions</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-customer-servlet-container-error-page">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>In the <a href="#webflux-web-handler-api"><code>WebHandler</code> API</a>, you can use a <code>WebExceptionHandler</code> to handle
exceptions from the chain of <code>WebFilter</code> instances and the target <code>WebHandler</code>. When using the
<a href="#webflux-config">WebFlux Config</a>, registering a <code>WebExceptionHandler</code> is as simple as declaring it as a
Spring bean and (optionally) expressing precedence by using <code>@Order</code> on the bean declaration or
by implementing <code>Ordered</code>.</p>
</div>
<div class="paragraph">
<p>The following table describes the available <code>WebExceptionHandler</code> implementations:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Exception Handler</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ResponseStatusExceptionHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Provides handling for exceptions of type
  <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/ResponseStatusException.html"><code>ResponseStatusException</code></a>
  by setting the response to the HTTP status code of the exception.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WebFluxResponseStatusExceptionHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Extension of <code>ResponseStatusExceptionHandler</code> that can also determine the HTTP status
  code of a <code>@ResponseStatus</code> annotation on any exception.</p>
<p class="tableblock">  This handler is declared in the <a href="#webflux-config">WebFlux Config</a>.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="webflux-codecs">1.2.5. Codecs</h4>
<div class="paragraph">
<p><span class="small"><a href="integration.html#rest-message-conversion">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <code>spring-web</code> and <code>spring-core</code> modules provide support for serializing and
deserializing byte content to and from higher level objects through non-blocking I/O with
Reactive Streams back pressure. The following describes this support:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/codec/Encoder.html"><code>Encoder</code></a> and
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/codec/Decoder.html"><code>Decoder</code></a> are low level contracts to
encode and decode content independent of HTTP.</p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/http/codec/HttpMessageReader.html"><code>HttpMessageReader</code></a> and
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/http/codec/HttpMessageWriter.html"><code>HttpMessageWriter</code></a> are contracts
to encode and decode HTTP message content.</p>
</li>
<li>
<p>An <code>Encoder</code> can be wrapped with <code>EncoderHttpMessageWriter</code> to adapt it for use in a web
application, while a <code>Decoder</code> can be wrapped with <code>DecoderHttpMessageReader</code>.</p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/io/buffer/DataBuffer.html"><code>DataBuffer</code></a> abstracts different
byte buffer representations (e.g. Netty <code>ByteBuf</code>, <code>java.nio.ByteBuffer</code>, etc.) and is
what all codecs work on. See <a href="core.html#databuffers">Data Buffers and Codecs</a> in the
"Spring Core" section for more on this topic.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>spring-core</code> module provides <code>byte[]</code>, <code>ByteBuffer</code>, <code>DataBuffer</code>, <code>Resource</code>, and
<code>String</code> encoder and decoder implementations. The <code>spring-web</code> module provides Jackson
JSON, Jackson Smile, JAXB2, Protocol Buffers and other encoders and decoders along with
web-only HTTP message reader and writer implementations for form data, multipart content,
server-sent events, and others.</p>
</div>
<div class="paragraph">
<p><code>ClientCodecConfigurer</code> and <code>ServerCodecConfigurer</code> are typically used to configure and
customize the codecs to use in an application. See the section on configuring
<a href="#webflux-config-message-codecs">HTTP message codecs</a>.</p>
</div>
<div class="sect4">
<h5 id="webflux-codecs-jackson">Jackson JSON</h5>
<div class="paragraph">
<p>JSON and binary JSON (<a href="https://github.com/FasterXML/smile-format-specification">Smile</a>) are
both supported when the Jackson library is present.</p>
</div>
<div class="paragraph">
<p>The <code>Jackson2Decoder</code> works as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Jackson&#8217;s asynchronous, non-blocking parser is used to aggregate a stream of byte chunks
into <code>TokenBuffer</code>'s each representing a JSON object.</p>
</li>
<li>
<p>Each <code>TokenBuffer</code> is passed to Jackson&#8217;s <code>ObjectMapper</code> to create a higher level object.</p>
</li>
<li>
<p>When decoding to a single-value publisher (e.g. <code>Mono</code>), there is one <code>TokenBuffer</code>.</p>
</li>
<li>
<p>When decoding to a multi-value publisher (e.g. <code>Flux</code>), each <code>TokenBuffer</code> is passed to
the <code>ObjectMapper</code> as soon as enough bytes are received for a fully formed object. The
input content can be a JSON array, or any
<a href="https://en.wikipedia.org/wiki/JSON_streaming">line-delimited JSON</a> format such as NDJSON,
JSON Lines, or JSON Text Sequences.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>Jackson2Encoder</code> works as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>For a single value publisher (e.g. <code>Mono</code>), simply serialize it through the
<code>ObjectMapper</code>.</p>
</li>
<li>
<p>For a multi-value publisher with <code>application/json</code>, by default collect the values with
<code>Flux#collectToList()</code> and then serialize the resulting collection.</p>
</li>
<li>
<p>For a multi-value publisher with a streaming media type such as
<code>application/x-ndjson</code> or <code>application/stream+x-jackson-smile</code>, encode, write, and
flush each value individually using a
<a href="https://en.wikipedia.org/wiki/JSON_streaming">line-delimited JSON</a> format. Other
streaming media types may be registered with the encoder.</p>
</li>
<li>
<p>For SSE the <code>Jackson2Encoder</code> is invoked per event and the output is flushed to ensure
delivery without delay.</p>
</li>
</ul>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>By default both <code>Jackson2Encoder</code> and <code>Jackson2Decoder</code> do not support elements of type
<code>String</code>. Instead the default assumption is that a string or a sequence of strings
represent serialized JSON content, to be rendered by the <code>CharSequenceEncoder</code>. If what
you need is to render a JSON array from <code>Flux&lt;String&gt;</code>, use <code>Flux#collectToList()</code> and
encode a <code>Mono&lt;List&lt;String&gt;&gt;</code>.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-codecs-forms">Form Data</h5>
<div class="paragraph">
<p><code>FormHttpMessageReader</code> and <code>FormHttpMessageWriter</code> support decoding and encoding
<code>application/x-www-form-urlencoded</code> content.</p>
</div>
<div class="paragraph">
<p>On the server side where form content often needs to be accessed from multiple places,
<code>ServerWebExchange</code> provides a dedicated <code>getFormData()</code> method that parses the content
through <code>FormHttpMessageReader</code> and then caches the result for repeated access.
See <a href="#webflux-form-data">Form Data</a> in the <a href="#webflux-web-handler-api"><code>WebHandler</code> API</a> section.</p>
</div>
<div class="paragraph">
<p>Once <code>getFormData()</code> is used, the original raw content can no longer be read from the
request body. For this reason, applications are expected to go through <code>ServerWebExchange</code>
consistently for access to the cached form data versus reading from the raw request body.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-codecs-multipart">Multipart</h5>
<div class="paragraph">
<p><code>MultipartHttpMessageReader</code> and <code>MultipartHttpMessageWriter</code> support decoding and
encoding "multipart/form-data" content. In turn <code>MultipartHttpMessageReader</code> delegates to
another <code>HttpMessageReader</code> for the actual parsing to a <code>Flux&lt;Part&gt;</code> and then simply
collects the parts into a <code>MultiValueMap</code>.
By default, the <code>DefaultPartHttpMessageReader</code> is used, but this can be changed through the
<code>ServerCodecConfigurer</code>.
For more information about the <code>DefaultPartHttpMessageReader</code>, refer to to the
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/http/codec/multipart/DefaultPartHttpMessageReader.html">javadoc of <code>DefaultPartHttpMessageReader</code></a>.</p>
</div>
<div class="paragraph">
<p>On the server side where multipart form content may need to be accessed from multiple
places, <code>ServerWebExchange</code> provides a dedicated <code>getMultipartData()</code> method that parses
the content through <code>MultipartHttpMessageReader</code> and then caches the result for repeated access.
See <a href="#webflux-multipart">Multipart Data</a> in the <a href="#webflux-web-handler-api"><code>WebHandler</code> API</a> section.</p>
</div>
<div class="paragraph">
<p>Once <code>getMultipartData()</code> is used, the original raw content can no longer be read from the
request body. For this reason applications have to consistently use <code>getMultipartData()</code>
for repeated, map-like access to parts, or otherwise rely on the
<code>SynchronossPartHttpMessageReader</code> for a one-time access to <code>Flux&lt;Part&gt;</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-codecs-limits">Limits</h5>
<div class="paragraph">
<p><code>Decoder</code> and <code>HttpMessageReader</code> implementations that buffer some or all of the input
stream can be configured with a limit on the maximum number of bytes to buffer in memory.
In some cases buffering occurs because input is aggregated and represented as a single
object — for example, a controller method with <code>@RequestBody byte[]</code>,
<code>x-www-form-urlencoded</code> data, and so on. Buffering can also occur with streaming, when
splitting the input stream — for example, delimited text, a stream of JSON objects, and
so on. For those streaming cases, the limit applies to the number of bytes associated
with one object in the stream.</p>
</div>
<div class="paragraph">
<p>To configure buffer sizes, you can check if a given <code>Decoder</code> or <code>HttpMessageReader</code>
exposes a <code>maxInMemorySize</code> property and if so the Javadoc will have details about default
values. On the server side, <code>ServerCodecConfigurer</code> provides a single place from where to
set all codecs, see <a href="#webflux-config-message-codecs">HTTP message codecs</a>. On the client side, the limit for
all codecs can be changed in
<a href="web-reactive.html#webflux-client-builder-maxinmemorysize">WebClient.Builder</a>.</p>
</div>
<div class="paragraph">
<p>For <a href="#webflux-codecs-multipart">Multipart parsing</a> the <code>maxInMemorySize</code> property limits
the size of non-file parts. For file parts, it determines the threshold at which the part
is written to disk. For file parts written to disk, there is an additional
<code>maxDiskUsagePerPart</code> property to limit the amount of disk space per part. There is also
a <code>maxParts</code> property to limit the overall number of parts in a multipart request.
To configure all three in WebFlux, you&#8217;ll need to supply a pre-configured instance of
<code>MultipartHttpMessageReader</code> to <code>ServerCodecConfigurer</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-codecs-streaming">Streaming</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-async-http-streaming">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>When streaming to the HTTP response (for example, <code>text/event-stream</code>,
<code>application/x-ndjson</code>), it is important to send data periodically, in order to
reliably detect a disconnected client sooner rather than later. Such a send could be a
comment-only, empty SSE event or any other "no-op" data that would effectively serve as
a heartbeat.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-codecs-buffers"><code>DataBuffer</code></h5>
<div class="paragraph">
<p><code>DataBuffer</code> is the representation for a byte buffer in WebFlux. The Spring Core part of
this reference has more on that in the section on
<a href="core.html#databuffers">Data Buffers and Codecs</a>. The key point to understand is that on some
servers like Netty, byte buffers are pooled and reference counted, and must be released
when consumed to avoid memory leaks.</p>
</div>
<div class="paragraph">
<p>WebFlux applications generally do not need to be concerned with such issues, unless they
consume or produce data buffers directly, as opposed to relying on codecs to convert to
and from higher level objects, or unless they choose to create custom codecs. For such
cases please review the information in <a href="core.html#databuffers">Data Buffers and Codecs</a>,
especially the section on <a href="core.html#databuffers-using">Using DataBuffer</a>.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-logging">1.2.6. Logging</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-logging">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>DEBUG</code> level logging in Spring WebFlux is designed to be compact, minimal, and
human-friendly. It focuses on high value bits of information that are useful over and
over again vs others that are useful only when debugging a specific issue.</p>
</div>
<div class="paragraph">
<p><code>TRACE</code> level logging generally follows the same principles as <code>DEBUG</code> (and for example also
should not be a firehose) but can be used for debugging any issue. In addition, some log
messages may show a different level of detail at <code>TRACE</code> vs <code>DEBUG</code>.</p>
</div>
<div class="paragraph">
<p>Good logging comes from the experience of using the logs. If you spot anything that does
not meet the stated goals, please let us know.</p>
</div>
<div class="sect4">
<h5 id="webflux-logging-id">Log Id</h5>
<div class="paragraph">
<p>In WebFlux, a single request can be run over multiple threads and the thread ID
is not useful for correlating log messages that belong to a specific request. This is why
WebFlux log messages are prefixed with a request-specific ID by default.</p>
</div>
<div class="paragraph">
<p>On the server side, the log ID is stored in the <code>ServerWebExchange</code> attribute
(<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/ServerWebExchange.html#LOG_ID_ATTRIBUTE"><code>LOG_ID_ATTRIBUTE</code></a>),
while a fully formatted prefix based on that ID is available from
<code>ServerWebExchange#getLogPrefix()</code>. On the <code>WebClient</code> side, the log ID is stored in the
<code>ClientRequest</code> attribute
(<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/function/client/ClientRequest.html#LOG_ID_ATTRIBUTE"><code>LOG_ID_ATTRIBUTE</code></a>)
,while a fully formatted prefix is available from <code>ClientRequest#logPrefix()</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-logging-sensitive-data">Sensitive Data</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-logging-sensitive-data">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>DEBUG</code> and <code>TRACE</code> logging can log sensitive information. This is why form parameters and
headers are masked by default and you must explicitly enable their logging in full.</p>
</div>
<div class="paragraph">
<p>The following example shows how to do so for server-side requests:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
class MyConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().enableLoggingRequestDetails(true);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class MyConfig : WebFluxConfigurer {

    override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
        configurer.defaultCodecs().enableLoggingRequestDetails(true)
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example shows how to do so for client-side requests:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Consumer&lt;ClientCodecConfigurer&gt; consumer = configurer -&gt;
        configurer.defaultCodecs().enableLoggingRequestDetails(true);

WebClient webClient = WebClient.builder()
        .exchangeStrategies(strategies -&gt; strategies.codecs(consumer))
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val consumer: (ClientCodecConfigurer) -&gt; Unit  = { configurer -&gt; configurer.defaultCodecs().enableLoggingRequestDetails(true) }

val webClient = WebClient.builder()
        .exchangeStrategies({ strategies -&gt; strategies.codecs(consumer) })
        .build()</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="webflux-logging-appenders">Appenders</h5>
<div class="paragraph">
<p>Logging libraries such as SLF4J and Log4J 2 provide asynchronous loggers that avoid
blocking. While those have their own drawbacks such as potentially dropping messages
that could not be queued for logging, they are the best available options currently
for use in a reactive, non-blocking application.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-codecs-custom">Custom codecs</h5>
<div class="paragraph">
<p>Applications can register custom codecs for supporting additional media types,
or specific behaviors that are not supported by the default codecs.</p>
</div>
<div class="paragraph">
<p>Some configuration options expressed by developers are enforced on default codecs.
Custom codecs might want to get a chance to align with those preferences,
like <a href="#webflux-codecs-limits">enforcing buffering limits</a>
or <a href="#webflux-logging-sensitive-data">logging sensitive data</a>.</p>
</div>
<div class="paragraph">
<p>The following example shows how to do so for client-side requests:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient webClient = WebClient.builder()
        .codecs(configurer -&gt; {
                CustomDecoder decoder = new CustomDecoder();
                configurer.customCodecs().registerWithDefaultConfig(decoder);
        })
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val webClient = WebClient.builder()
        .codecs({ configurer -&gt;
                val decoder = CustomDecoder()
                configurer.customCodecs().registerWithDefaultConfig(decoder)
         })
        .build()</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-dispatcher-handler">1.3. <code>DispatcherHandler</code></h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-servlet">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux, similarly to Spring MVC, is designed around the front controller pattern,
where a central <code>WebHandler</code>, the <code>DispatcherHandler</code>, provides a shared algorithm for
request processing, while actual work is performed by configurable, delegate components.
This model is flexible and supports diverse workflows.</p>
</div>
<div class="paragraph">
<p><code>DispatcherHandler</code> discovers the delegate components it needs from Spring configuration.
It is also designed to be a Spring bean itself and implements <code>ApplicationContextAware</code>
for access to the context in which it runs. If <code>DispatcherHandler</code> is declared with a bean
name of <code>webHandler</code>, it is, in turn, discovered by
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/server/adapter/WebHttpHandlerBuilder.html"><code>WebHttpHandlerBuilder</code></a>,
which puts together a request-processing chain, as described in <a href="#webflux-web-handler-api"><code>WebHandler</code> API</a>.</p>
</div>
<div class="paragraph">
<p>Spring configuration in a WebFlux application typically contains:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>DispatcherHandler</code> with the bean name <code>webHandler</code></p>
</li>
<li>
<p><code>WebFilter</code> and <code>WebExceptionHandler</code> beans</p>
</li>
<li>
<p><a href="#webflux-special-bean-types"><code>DispatcherHandler</code> special beans</a></p>
</li>
<li>
<p>Others</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The configuration is given to <code>WebHttpHandlerBuilder</code> to build the processing chain,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">ApplicationContext context = ...
HttpHandler handler = WebHttpHandlerBuilder.applicationContext(context).build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val context: ApplicationContext = ...
val handler = WebHttpHandlerBuilder.applicationContext(context).build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The resulting <code>HttpHandler</code> is ready for use with a <a href="#webflux-httphandler">server adapter</a>.</p>
</div>
<div class="sect3">
<h4 id="webflux-special-bean-types">1.3.1. Special Bean Types</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-servlet-special-bean-types">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <code>DispatcherHandler</code> delegates to special beans to process requests and render the
appropriate responses. By &#8220;special beans,&#8221; we mean Spring-managed <code>Object</code> instances that
implement WebFlux framework contracts. Those usually come with built-in contracts, but
you can customize their properties, extend them, or replace them.</p>
</div>
<div class="paragraph">
<p>The following table lists the special beans detected by the <code>DispatcherHandler</code>. Note that
there are also some other beans detected at a lower level (see
<a href="#webflux-web-handler-api-special-beans">Special bean types</a> in the Web Handler API).</p>
</div>
<table id="webflux-special-beans-table" class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Bean type</th>
<th class="tableblock halign-left valign-top">Explanation</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HandlerMapping</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Map a request to a handler. The mapping is based on some criteria, the details of
  which vary by <code>HandlerMapping</code> implementation&#8201;&#8212;&#8201;annotated controllers, simple
  URL pattern mappings, and others.</p>
<p class="tableblock">  The main <code>HandlerMapping</code> implementations are <code>RequestMappingHandlerMapping</code> for
  <code>@RequestMapping</code> annotated methods, <code>RouterFunctionMapping</code> for functional endpoint
  routes, and <code>SimpleUrlHandlerMapping</code> for explicit registrations of URI path patterns
  and <code>WebHandler</code> instances.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HandlerAdapter</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Help the <code>DispatcherHandler</code> to invoke a handler mapped to a request regardless of
  how the handler is actually invoked. For example, invoking an annotated controller
  requires resolving annotations. The main purpose of a <code>HandlerAdapter</code> is to shield the
  <code>DispatcherHandler</code> from such details.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HandlerResultHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Process the result from the handler invocation and finalize the response.
  See <a href="#webflux-resulthandling">Result Handling</a>.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="webflux-framework-config">1.3.2. WebFlux Config</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-servlet-config">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Applications can declare the infrastructure beans (listed under
<a href="#webflux-web-handler-api-special-beans">Web Handler API</a> and
<a href="#webflux-special-bean-types"><code>DispatcherHandler</code></a>) that are required to process requests.
However, in most cases, the <a href="#webflux-config">WebFlux Config</a> is the best starting point. It declares the
required beans and provides a higher-level configuration callback API to customize it.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Spring Boot relies on the WebFlux config to configure Spring WebFlux and also provides
many extra convenient options.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-dispatcher-handler-sequence">1.3.3. Processing</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-servlet-sequence">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>DispatcherHandler</code> processes requests as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Each <code>HandlerMapping</code> is asked to find a matching handler, and the first match is used.</p>
</li>
<li>
<p>If a handler is found, it is run through an appropriate <code>HandlerAdapter</code>, which
exposes the return value from the execution as <code>HandlerResult</code>.</p>
</li>
<li>
<p>The <code>HandlerResult</code> is given to an appropriate <code>HandlerResultHandler</code> to complete
processing by writing to the response directly or by using a view to render.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="webflux-resulthandling">1.3.4. Result Handling</h4>
<div class="paragraph">
<p>The return value from the invocation of a handler, through a <code>HandlerAdapter</code>, is wrapped
as a <code>HandlerResult</code>, along with some additional context, and passed to the first
<code>HandlerResultHandler</code> that claims support for it. The following table shows the available
<code>HandlerResultHandler</code> implementations, all of which are declared in the <a href="#webflux-config">WebFlux Config</a>:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 50%;">
<col style="width: 25%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Result Handler Type</th>
<th class="tableblock halign-left valign-top">Return Values</th>
<th class="tableblock halign-left valign-top">Default Order</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ResponseEntityResultHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ResponseEntity</code>, typically from <code>@Controller</code> instances.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ServerResponseResultHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ServerResponse</code>, typically from functional endpoints.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ResponseBodyResultHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Handle return values from <code>@ResponseBody</code> methods or <code>@RestController</code> classes.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">100</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ViewResolutionResultHandler</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>CharSequence</code>, <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/result/view/View.html"><code>View</code></a>,
  <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/ui/Model.html">Model</a>, <code>Map</code>,
  <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/result/view/Rendering.html">Rendering</a>,
  or any other <code>Object</code> is treated as a model attribute.</p>
<p class="tableblock">  See also <a href="#webflux-viewresolution">View Resolution</a>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Integer.MAX_VALUE</code></p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="webflux-dispatcher-exceptions">1.3.5. Exceptions</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-exceptionhandlers">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <code>HandlerResult</code> returned from a <code>HandlerAdapter</code> can expose a function for error
handling based on some handler-specific mechanism. This error function is called if:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The handler (for example, <code>@Controller</code>) invocation fails.</p>
</li>
<li>
<p>The handling of the handler return value through a <code>HandlerResultHandler</code> fails.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The error function can change the response (for example, to an error status), as long as an error
signal occurs before the reactive type returned from the handler produces any data items.</p>
</div>
<div class="paragraph">
<p>This is how <code>@ExceptionHandler</code> methods in <code>@Controller</code> classes are supported.
By contrast, support for the same in Spring MVC is built on a <code>HandlerExceptionResolver</code>.
This generally should not matter. However, keep in mind that, in WebFlux, you cannot use a
<code>@ControllerAdvice</code> to handle exceptions that occur before a handler is chosen.</p>
</div>
<div class="paragraph">
<p>See also <a href="#webflux-ann-controller-exceptions">Managing Exceptions</a> in the &#8220;Annotated Controller&#8221; section or
<a href="#webflux-exception-handler">Exceptions</a> in the WebHandler API section.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-viewresolution">1.3.6. View Resolution</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-viewresolver">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>View resolution enables rendering to a browser with an HTML template and a model without
tying you to a specific view technology. In Spring WebFlux, view resolution is
supported through a dedicated <a href="#webflux-resulthandling">HandlerResultHandler</a> that uses
  <code>ViewResolver</code> instances to map a String (representing a logical view name) to a <code>View</code>
instance. The <code>View</code> is then used to render the response.</p>
</div>
<div class="sect4">
<h5 id="webflux-viewresolution-handling">Handling</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-handling">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <code>HandlerResult</code> passed into <code>ViewResolutionResultHandler</code> contains the return value
from the handler and the model that contains attributes added during request
handling. The return value is processed as one of the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>String</code>, <code>CharSequence</code>: A logical view name to be resolved to a <code>View</code> through
the list of configured <code>ViewResolver</code> implementations.</p>
</li>
<li>
<p><code>void</code>: Select a default view name based on the request path, minus the leading and
trailing slash, and resolve it to a <code>View</code>. The same also happens when a view name
was not provided (for example, model attribute was returned) or an async return value
(for example, <code>Mono</code> completed empty).</p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/result/view/Rendering.html">Rendering</a>: API for
view resolution scenarios. Explore the options in your IDE with code completion.</p>
</li>
<li>
<p><code>Model</code>, <code>Map</code>: Extra model attributes to be added to the model for the request.</p>
</li>
<li>
<p>Any other: Any other return value (except for simple types, as determined by
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-">BeanUtils#isSimpleProperty</a>)
is treated as a model attribute to be added to the model. The attribute name is derived
from the class name by using <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/Conventions.html">conventions</a>,
unless a handler method <code>@ModelAttribute</code> annotation is present.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The model can contain asynchronous, reactive types (for example, from Reactor or RxJava). Prior
to rendering, <code>AbstractView</code> resolves such model attributes into concrete values
and updates the model. Single-value reactive types are resolved to a single
value or no value (if empty), while multi-value reactive types (for example, <code>Flux&lt;T&gt;</code>) are
collected and resolved to <code>List&lt;T&gt;</code>.</p>
</div>
<div class="paragraph">
<p>To configure view resolution is as simple as adding a <code>ViewResolutionResultHandler</code> bean
to your Spring configuration. <a href="#webflux-config-view-resolvers">WebFlux Config</a> provides a
dedicated configuration API for view resolution.</p>
</div>
<div class="paragraph">
<p>See <a href="#webflux-view">View Technologies</a> for more on the view technologies integrated with Spring WebFlux.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-redirecting-redirect-prefix">Redirecting</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-redirecting-redirect-prefix">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The special <code>redirect:</code> prefix in a view name lets you perform a redirect. The
<code>UrlBasedViewResolver</code> (and sub-classes) recognize this as an instruction that a
redirect is needed. The rest of the view name is the redirect URL.</p>
</div>
<div class="paragraph">
<p>The net effect is the same as if the controller had returned a <code>RedirectView</code> or
<code>Rendering.redirectTo("abc").build()</code>, but now the controller itself can
operate in terms of logical view names. A view name such as
<code>redirect:/some/resource</code> is relative to the current application, while a view name such as
<code>redirect:https://example.com/arbitrary/path</code> redirects to an absolute URL.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-multiple-representations">Content Negotiation</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-multiple-representations">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>ViewResolutionResultHandler</code> supports content negotiation. It compares the request
media types with the media types supported by each selected <code>View</code>. The first <code>View</code>
that supports the requested media type(s) is used.</p>
</div>
<div class="paragraph">
<p>In order to support media types such as JSON and XML, Spring WebFlux provides
<code>HttpMessageWriterView</code>, which is a special <code>View</code> that renders through an
<a href="#webflux-codecs">HttpMessageWriter</a>. Typically, you would configure these as default
views through the <a href="#webflux-config-view-resolvers">WebFlux Configuration</a>. Default views are
always selected and used if they match the requested media type.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-controller">1.4. Annotated Controllers</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-controller">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux provides an annotation-based programming model, where <code>@Controller</code> and
<code>@RestController</code> components use annotations to express request mappings, request input,
handle exceptions, and more. Annotated controllers have flexible method signatures and
do not have to extend base classes nor implement specific interfaces.</p>
</div>
<div class="paragraph">
<p>The following listing shows a basic example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@RestController
public class HelloController {

    @GetMapping("/hello")
    public String handle() {
        return "Hello WebFlux";
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@RestController
class HelloController {

    @GetMapping("/hello")
    fun handle() = "Hello WebFlux"
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In the preceding example, the method returns a <code>String</code> to be written to the response body.</p>
</div>
<div class="sect3">
<h4 id="webflux-ann-controller">1.4.1. <code>@Controller</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-controller">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can define controller beans by using a standard Spring bean definition.
The <code>@Controller</code> stereotype allows for auto-detection and is aligned with Spring general support
for detecting <code>@Component</code> classes in the classpath and auto-registering bean definitions
for them. It also acts as a stereotype for the annotated class, indicating its role as
a web component.</p>
</div>
<div class="paragraph">
<p>To enable auto-detection of such <code>@Controller</code> beans, you can add component scanning to
your Java configuration, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@ComponentScan("org.example.web") <i class="conum" data-value="1"></i><b>(1)</b>
public class WebConfig {

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Scan the <code>org.example.web</code> package.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@ComponentScan("org.example.web") <i class="conum" data-value="1"></i><b>(1)</b>
class WebConfig {

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Scan the <code>org.example.web</code> package.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>@RestController</code> is a <a href="core.html#beans-meta-annotations">composed annotation</a> that is
itself meta-annotated with <code>@Controller</code> and <code>@ResponseBody</code>, indicating a controller whose
every method inherits the type-level <code>@ResponseBody</code> annotation and, therefore, writes
directly to the response body versus view resolution and rendering with an HTML template.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-ann-requestmapping">1.4.2. Request Mapping</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <code>@RequestMapping</code> annotation is used to map requests to controllers methods. It has
various attributes to match by URL, HTTP method, request parameters, headers, and media
types. You can use it at the class level to express shared mappings or at the method level
to narrow down to a specific endpoint mapping.</p>
</div>
<div class="paragraph">
<p>There are also HTTP method specific shortcut variants of <code>@RequestMapping</code>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>@GetMapping</code></p>
</li>
<li>
<p><code>@PostMapping</code></p>
</li>
<li>
<p><code>@PutMapping</code></p>
</li>
<li>
<p><code>@DeleteMapping</code></p>
</li>
<li>
<p><code>@PatchMapping</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The preceding annotations are <a href="#webflux-ann-requestmapping-composed">Custom Annotations</a> that are provided
because, arguably, most controller methods should be mapped to a specific HTTP method versus
using <code>@RequestMapping</code>, which, by default, matches to all HTTP methods. At the same time, a
<code>@RequestMapping</code> is still needed at the class level to express shared mappings.</p>
</div>
<div class="paragraph">
<p>The following example uses type and method level mappings:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@RestController
@RequestMapping("/persons")
class PersonController {

    @GetMapping("/{id}")
    public Person getPerson(@PathVariable Long id) {
        // ...
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void add(@RequestBody Person person) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@RestController
@RequestMapping("/persons")
class PersonController {

    @GetMapping("/{id}")
    fun getPerson(@PathVariable id: Long): Person {
        // ...
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    fun add(@RequestBody person: Person) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-uri-templates">URI Patterns</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-uri-templates">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can map requests by using glob patterns and wildcards:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 20%;">
<col style="width: 30%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Pattern</th>
<th class="tableblock halign-left valign-top">Description</th>
<th class="tableblock halign-left valign-top">Example</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>?</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Matches one character</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"/pages/t?st.html"</code> matches <code>"/pages/test.html"</code> and <code>"/pages/t3st.html"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>*</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Matches zero or more characters within a path segment</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"/resources/*.png"</code> matches <code>"/resources/file.png"</code></p>
<p class="tableblock"><code>"/projects/*/versions"</code> matches <code>"/projects/spring/versions"</code> but does not match <code>"/projects/spring/boot/versions"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>**</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Matches zero or more path segments until the end of the path</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"/resources/**"</code> matches <code>"/resources/file.png"</code> and <code>"/resources/images/file.png"</code></p>
<p class="tableblock"><code>"/resources/**/file.png"</code> is invalid as <code>**</code> is only allowed at the end of the path.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>{name}</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Matches a path segment and captures it as a variable named "name"</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"/projects/{project}/versions"</code> matches <code>"/projects/spring/versions"</code> and captures <code>project=spring</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>{name:[a-z]+}</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Matches the regexp <code>"[a-z]+"</code> as a path variable named "name"</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"/projects/{project:[a-z]+}/versions"</code> matches <code>"/projects/spring/versions"</code> but not <code>"/projects/spring1/versions"</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>{*path}</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Matches zero or more path segments until the end of the path and captures it as a variable named "path"</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>"/resources/{*file}"</code> matches <code>"/resources/images/file.png"</code> and captures <code>file=images/file.png</code></p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Captured URI variables can be accessed with <code>@PathVariable</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/owners/{ownerId}/pets/{petId}")
public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can declare URI variables at the class and method levels, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
@RequestMapping("/owners/{ownerId}") <i class="conum" data-value="1"></i><b>(1)</b>
public class OwnerController {

    @GetMapping("/pets/{petId}") <i class="conum" data-value="2"></i><b>(2)</b>
    public Pet findPet(@PathVariable Long ownerId, @PathVariable Long petId) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Class-level URI mapping.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Method-level URI mapping.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
@RequestMapping("/owners/{ownerId}") <i class="conum" data-value="1"></i><b>(1)</b>
class OwnerController {

    @GetMapping("/pets/{petId}") <i class="conum" data-value="2"></i><b>(2)</b>
    fun findPet(@PathVariable ownerId: Long, @PathVariable petId: Long): Pet {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Class-level URI mapping.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Method-level URI mapping.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>URI variables are automatically converted to the appropriate type or a <code>TypeMismatchException</code>
is raised. Simple types (<code>int</code>, <code>long</code>, <code>Date</code>, and so on) are supported by default and you can
register support for any other data type.
See <a href="#webflux-ann-typeconversion">Type Conversion</a> and <a href="#webflux-ann-initbinder"><code>DataBinder</code></a>.</p>
</div>
<div class="paragraph">
<p>URI variables can be named explicitly (for example, <code>@PathVariable("customId")</code>), but you can
leave that detail out if the names are the same and you compile your code with debugging
information or with the <code>-parameters</code> compiler flag on Java 8.</p>
</div>
<div class="paragraph">
<p>The syntax <code>{*varName}</code> declares a URI variable that matches zero or more remaining path
segments. For example <code>/resources/{*path}</code> matches all files under <code>/resources/</code>, and the
<code>"path"</code> variable captures the complete relative path.</p>
</div>
<div class="paragraph">
<p>The syntax <code>{varName:regex}</code> declares a URI variable with a regular expression that has the
syntax: <code>{varName:regex}</code>. For example, given a URL of <code>/spring-web-3.0.5 .jar</code>, the following method
extracts the name, version, and file extension:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
public void handle(@PathVariable String version, @PathVariable String ext) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/{name:[a-z-]+}-{version:\\d\\.\\d\\.\\d}{ext:\\.[a-z]+}")
fun handle(@PathVariable version: String, @PathVariable ext: String) {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>URI path patterns can also have embedded <code>${&#8230;&#8203;}</code> placeholders that are resolved on startup
through <code>PropertyPlaceHolderConfigurer</code> against local, system, environment, and other property
sources. You ca use this to, for example, parameterize a base URL based on some external
configuration.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Spring WebFlux uses <code>PathPattern</code> and the <code>PathPatternParser</code> for URI path matching support.
Both classes are located in <code>spring-web</code> and are expressly designed for use with HTTP URL
paths in web applications where a large number of URI path patterns are matched at runtime.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Spring WebFlux does not support suffix pattern matching&#8201;&#8212;&#8201;unlike Spring MVC, where a
mapping such as <code>/person</code> also matches to <code>/person.*</code>. For URL-based content
negotiation, if needed, we recommend using a query parameter, which is simpler, more
explicit, and less vulnerable to URL path based exploits.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-pattern-comparison">Pattern Comparison</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-pattern-comparison">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>When multiple patterns match a URL, they must be compared to find the best match. This is done
with <code>PathPattern.SPECIFICITY_COMPARATOR</code>, which looks for patterns that are more specific.</p>
</div>
<div class="paragraph">
<p>For every pattern, a score is computed, based on the number of URI variables and wildcards,
where a URI variable scores lower than a wildcard. A pattern with a lower total score
wins. If two patterns have the same score, the longer is chosen.</p>
</div>
<div class="paragraph">
<p>Catch-all patterns (for example, <code>**</code>, <code>{*varName}</code>) are excluded from the scoring and are always
sorted last instead. If two patterns are both catch-all, the longer is chosen.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-consumes">Consumable Media Types</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-consumes">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can narrow the request mapping based on the <code>Content-Type</code> of the request,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping(path = "/pets", consumes = "application/json")
public void addPet(@RequestBody Pet pet) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/pets", consumes = ["application/json"])
fun addPet(@RequestBody pet: Pet) {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The consumes attribute also supports negation expressions&#8201;&#8212;&#8201;for example, <code>!text/plain</code> means any
content type other than <code>text/plain</code>.</p>
</div>
<div class="paragraph">
<p>You can declare a shared <code>consumes</code> attribute at the class level. Unlike most other request
mapping attributes, however, when used at the class level, a method-level <code>consumes</code> attribute
overrides rather than extends the class-level declaration.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<code>MediaType</code> provides constants for commonly used media types&#8201;&#8212;&#8201;for example,
<code>APPLICATION_JSON_VALUE</code> and <code>APPLICATION_XML_VALUE</code>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-produces">Producible Media Types</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-produces">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can narrow the request mapping based on the <code>Accept</code> request header and the list of
content types that a controller method produces, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping(path = "/pets/{petId}", produces = "application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/pets/{petId}", produces = ["application/json"])
@ResponseBody
fun getPet(@PathVariable String petId): Pet {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The media type can specify a character set. Negated expressions are supported&#8201;&#8212;&#8201;for example,
<code>!text/plain</code> means any content type other than <code>text/plain</code>.</p>
</div>
<div class="paragraph">
<p>You can declare a shared <code>produces</code> attribute at the class level. Unlike most other request
mapping attributes, however, when used at the class level, a method-level <code>produces</code> attribute
overrides rather than extend the class level declaration.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<code>MediaType</code> provides constants for commonly used media types&#8201;&#8212;&#8201;e.g.
<code>APPLICATION_JSON_VALUE</code>, <code>APPLICATION_XML_VALUE</code>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-params-and-headers">Parameters and Headers</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-params-and-headers">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can narrow request mappings based on query parameter conditions. You can test for the
presence of a query parameter (<code>myParam</code>), for its absence (<code>!myParam</code>), or for a
specific value (<code>myParam=myValue</code>). The following examples tests for a parameter with a value:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping(path = "/pets/{petId}", params = "myParam=myValue") <i class="conum" data-value="1"></i><b>(1)</b>
public void findPet(@PathVariable String petId) {
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Check that <code>myParam</code> equals <code>myValue</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/pets/{petId}", params = ["myParam=myValue"]) <i class="conum" data-value="1"></i><b>(1)</b>
fun findPet(@PathVariable petId: String) {
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Check that <code>myParam</code> equals <code>myValue</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You can also use the same with request header conditions, as the follwing example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping(path = "/pets", headers = "myHeader=myValue") <i class="conum" data-value="1"></i><b>(1)</b>
public void findPet(@PathVariable String petId) {
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Check that <code>myHeader</code> equals <code>myValue</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/pets", headers = ["myHeader=myValue"]) <i class="conum" data-value="1"></i><b>(1)</b>
fun findPet(@PathVariable petId: String) {
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Check that <code>myHeader</code> equals <code>myValue</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-head-options">HTTP HEAD, OPTIONS</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-head-options">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>@GetMapping</code> and <code>@RequestMapping(method=HttpMethod.GET)</code> support HTTP HEAD
transparently for request mapping purposes. Controller methods need not change.
A response wrapper, applied in the <code>HttpHandler</code> server adapter, ensures a <code>Content-Length</code>
header is set to the number of bytes written without actually writing to the response.</p>
</div>
<div class="paragraph">
<p>By default, HTTP OPTIONS is handled by setting the <code>Allow</code> response header to the list of HTTP
methods listed in all <code>@RequestMapping</code> methods with matching URL patterns.</p>
</div>
<div class="paragraph">
<p>For a <code>@RequestMapping</code> without HTTP method declarations, the <code>Allow</code> header is set to
<code>GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS</code>. Controller methods should always declare the
supported HTTP methods (for example, by using the HTTP method specific variants&#8201;&#8212;&#8201;<code>@GetMapping</code>, <code>@PostMapping</code>, and others).</p>
</div>
<div class="paragraph">
<p>You can explicitly map a <code>@RequestMapping</code> method to HTTP HEAD and HTTP OPTIONS, but that
is not necessary in the common case.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-composed">Custom Annotations</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-composed">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux supports the use of <a href="core.html#beans-meta-annotations">composed annotations</a>
for request mapping. Those are annotations that are themselves meta-annotated with
<code>@RequestMapping</code> and composed to redeclare a subset (or all) of the <code>@RequestMapping</code>
attributes with a narrower, more specific purpose.</p>
</div>
<div class="paragraph">
<p><code>@GetMapping</code>, <code>@PostMapping</code>, <code>@PutMapping</code>, <code>@DeleteMapping</code>, and <code>@PatchMapping</code> are
examples of composed annotations. They are provided, because, arguably, most
controller methods should be mapped to a specific HTTP method versus using <code>@RequestMapping</code>,
which, by default, matches to all HTTP methods. If you need an example of composed
annotations, look at how those are declared.</p>
</div>
<div class="paragraph">
<p>Spring WebFlux also supports custom request mapping attributes with custom request matching
logic. This is a more advanced option that requires sub-classing
<code>RequestMappingHandlerMapping</code> and overriding the <code>getCustomMethodCondition</code> method, where
you can check the custom attribute and return your own <code>RequestCondition</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestmapping-registration">Explicit Registrations</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestmapping-registration">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can programmatically register Handler methods, which can be used for dynamic
registrations or for advanced cases, such as different instances of the same handler
under different URLs. The following example shows how to do so:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
public class MyConfig {

    @Autowired
    public void setHandlerMapping(RequestMappingHandlerMapping mapping, UserHandler handler) <i class="conum" data-value="1"></i><b>(1)</b>
            throws NoSuchMethodException {

        RequestMappingInfo info = RequestMappingInfo
                .paths("/user/{id}").methods(RequestMethod.GET).build(); <i class="conum" data-value="2"></i><b>(2)</b>

        Method method = UserHandler.class.getMethod("getUser", Long.class); <i class="conum" data-value="3"></i><b>(3)</b>

        mapping.registerMapping(info, handler, method); <i class="conum" data-value="4"></i><b>(4)</b>
    }

}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Inject target handlers and the handler mapping for controllers.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Prepare the request mapping metadata.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Get the handler method.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Add the registration.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class MyConfig {

    @Autowired
    fun setHandlerMapping(mapping: RequestMappingHandlerMapping, handler: UserHandler) { <i class="conum" data-value="1"></i><b>(1)</b>

        val info = RequestMappingInfo.paths("/user/{id}").methods(RequestMethod.GET).build() <i class="conum" data-value="2"></i><b>(2)</b>

        val method = UserHandler::class.java.getMethod("getUser", Long::class.java) <i class="conum" data-value="3"></i><b>(3)</b>

        mapping.registerMapping(info, handler, method) <i class="conum" data-value="4"></i><b>(4)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Inject target handlers and the handler mapping for controllers.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Prepare the request mapping metadata.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Get the handler method.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Add the registration.</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-ann-methods">1.4.3. Handler Methods</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-methods">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>@RequestMapping</code> handler methods have a flexible signature and can choose from a range of
supported controller method arguments and return values.</p>
</div>
<div class="sect4">
<h5 id="webflux-ann-arguments">Method Arguments</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-arguments">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The following table shows the supported controller method arguments.</p>
</div>
<div class="paragraph">
<p>Reactive types (Reactor, RxJava, <a href="#webflux-reactive-libraries">or other</a>) are
supported on arguments that require blocking I/O (for example, reading the request body) to
be resolved. This is marked in the Description column. Reactive types are not expected
on arguments that do not require blocking.</p>
</div>
<div class="paragraph">
<p>JDK 1.8&#8217;s <code>java.util.Optional</code> is supported as a method argument in combination with
annotations that have a <code>required</code> attribute (for example, <code>@RequestParam</code>, <code>@RequestHeader</code>,
and others) and is equivalent to <code>required=false</code>.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Controller method argument</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ServerWebExchange</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Access to the full <code>ServerWebExchange</code>&#8201;&#8212;&#8201;container for the HTTP request and response,
  request and session attributes, <code>checkNotModified</code> methods, and others.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>ServerHttpRequest</code>, <code>ServerHttpResponse</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Access to the HTTP request or response.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>WebSession</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Access to the session. This does not force the start of a new session unless attributes
  are added. Supports reactive types.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>java.security.Principal</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The currently authenticated user&#8201;&#8212;&#8201;possibly a specific <code>Principal</code> implementation class if known.
  Supports reactive types.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>org.springframework.http.HttpMethod</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The HTTP method of the request.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>java.util.Locale</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The current request locale, determined by the most specific <code>LocaleResolver</code> available&#8201;&#8212;&#8201;in
  effect, the configured <code>LocaleResolver</code>/<code>LocaleContextResolver</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>java.util.TimeZone</code> + <code>java.time.ZoneId</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The time zone associated with the current request, as determined by a <code>LocaleContextResolver</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@PathVariable</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to URI template variables. See <a href="#webflux-ann-requestmapping-uri-templates">URI Patterns</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@MatrixVariable</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to name-value pairs in URI path segments. See <a href="#webflux-ann-matrix-variables">Matrix Variables</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@RequestParam</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to Servlet request parameters. Parameter values are converted to the declared
  method argument type. See <a href="#webflux-ann-requestparam"><code>@RequestParam</code></a>.</p>
<p class="tableblock">  Note that use of <code>@RequestParam</code> is optional&#8201;&#8212;&#8201;for example, to set its attributes.
  See &#8220;Any other argument&#8221; later in this table.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@RequestHeader</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to request headers. Header values are converted to the declared method argument
  type. See <a href="#webflux-ann-requestheader"><code>@RequestHeader</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@CookieValue</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to cookies. Cookie values are converted to the declared method argument type.
  See <a href="#webflux-ann-cookievalue"><code>@CookieValue</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@RequestBody</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to the HTTP request body. Body content is converted to the declared method
  argument type by using <code>HttpMessageReader</code> instances. Supports reactive types.
  See <a href="#webflux-ann-requestbody"><code>@RequestBody</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HttpEntity&lt;B&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to request headers and body. The body is converted with <code>HttpMessageReader</code> instances.
  Supports reactive types. See <a href="#webflux-ann-httpentity"><code>HttpEntity</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@RequestPart</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to a part in  a <code>multipart/form-data</code> request. Supports reactive types.
  See <a href="#webflux-multipart-forms">Multipart Content</a> and <a href="#webflux-multipart">Multipart Data</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>java.util.Map</code>, <code>org.springframework.ui.Model</code>, and <code>org.springframework.ui.ModelMap</code>.</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to the model that is used in HTML controllers and is exposed to templates as
  part of view rendering.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@ModelAttribute</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to an existing attribute in the model (instantiated if not present) with
  data binding and validation applied. See <a href="#webflux-ann-modelattrib-method-args"><code>@ModelAttribute</code></a> as well
  as <a href="#webflux-ann-modelattrib-methods"><code>Model</code></a> and <a href="#webflux-ann-initbinder"><code>DataBinder</code></a>.</p>
<p class="tableblock">  Note that use of <code>@ModelAttribute</code> is optional&#8201;&#8212;&#8201;for example, to set its attributes.
  See &#8220;Any other argument&#8221; later in this table.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Errors</code>, <code>BindingResult</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to errors from validation and data binding for a command object, i.e. a
  <code>@ModelAttribute</code> argument. An <code>Errors</code>, or <code>BindingResult</code> argument must be declared
  immediately after the validated method argument.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>SessionStatus</code> + class-level <code>@SessionAttributes</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For marking form processing complete, which triggers cleanup of session attributes
  declared through a class-level <code>@SessionAttributes</code> annotation.
  See <a href="#webflux-ann-sessionattributes"><code>@SessionAttributes</code></a> for more details.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>UriComponentsBuilder</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For preparing a URL relative to the current request&#8217;s host, port, scheme, and
  context path. See <a href="#webflux-uri-building">URI Links</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@SessionAttribute</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to any session attribute&#8201;&#8212;&#8201;in contrast to model attributes stored in the session
  as a result of a class-level <code>@SessionAttributes</code> declaration. See
  <a href="#webflux-ann-sessionattribute"><code>@SessionAttribute</code></a> for more details.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@RequestAttribute</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For access to request attributes. See <a href="#webflux-ann-requestattrib"><code>@RequestAttribute</code></a> for more details.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Any other argument</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">If a method argument is not matched to any of the above, it is, by default, resolved as
  a <code>@RequestParam</code> if it is a simple type, as determined by
  <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-">BeanUtils#isSimpleProperty</a>,
  or as a <code>@ModelAttribute</code>, otherwise.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect4">
<h5 id="webflux-ann-return-types">Return Values</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-return-types">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The following table shows the supported controller method return values. Note that reactive
types from libraries such as Reactor, RxJava, <a href="#webflux-reactive-libraries">or other</a> are
generally supported for all return values.</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 66.6667%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Controller method return value</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@ResponseBody</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The return value is encoded through <code>HttpMessageWriter</code> instances and written to the response.
  See <a href="#webflux-ann-responsebody"><code>@ResponseBody</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HttpEntity&lt;B&gt;</code>, <code>ResponseEntity&lt;B&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The return value specifies the full response, including HTTP headers, and the body is encoded
  through <code>HttpMessageWriter</code> instances and written to the response.
  See <a href="#webflux-ann-responseentity"><code>ResponseEntity</code></a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>HttpHeaders</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For returning a response with headers and no body.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>String</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A view name to be resolved with <code>ViewResolver</code> instances and used together with the implicit
  model&#8201;&#8212;&#8201;determined through command objects and <code>@ModelAttribute</code> methods. The handler
  method can also programmatically enrich the model by declaring a <code>Model</code> argument
  (described <a href="#webflux-viewresolution-handling">earlier</a>).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>View</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A <code>View</code> instance to use for rendering together with the implicit model&#8201;&#8212;&#8201;determined
  through command objects and <code>@ModelAttribute</code> methods. The handler method can also
  programmatically enrich the model by declaring a <code>Model</code> argument
  (described <a href="#webflux-viewresolution-handling">earlier</a>).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>java.util.Map</code>, <code>org.springframework.ui.Model</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Attributes to be added to the implicit model, with the view name implicitly determined
  based on the request path.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@ModelAttribute</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">An attribute to be added to the model, with the view name implicitly determined based
  on the request path.</p>
<p class="tableblock">  Note that <code>@ModelAttribute</code> is optional. See &#8220;Any other return value&#8221; later in
  this table.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Rendering</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">An API for model and view rendering scenarios.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>void</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A method with a <code>void</code>, possibly asynchronous (for example, <code>Mono&lt;Void&gt;</code>), return type (or a <code>null</code> return
  value) is considered to have fully handled the response if it also has a <code>ServerHttpResponse</code>,
  a <code>ServerWebExchange</code> argument, or an <code>@ResponseStatus</code> annotation. The same is also true
  if the controller has made a positive ETag or <code>lastModified</code> timestamp check.
  // TODO: See <a href="#webflux-caching-etag-lastmodified">Controllers</a> for details.</p>
<p class="tableblock">  If none of the above is true, a <code>void</code> return type can also indicate &#8220;no response body&#8221; for
  REST controllers or default view name selection for HTML controllers.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Flux&lt;ServerSentEvent&gt;</code>, <code>Observable&lt;ServerSentEvent&gt;</code>, or other reactive type</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Emit server-sent events. The <code>ServerSentEvent</code> wrapper can be omitted when only data needs
  to be written (however, <code>text/event-stream</code> must be requested or declared in the mapping
  through the <code>produces</code> attribute).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Any other return value</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">If a return value is not matched to any of the above, it is, by default, treated as a view
  name, if it is <code>String</code> or <code>void</code> (default view name selection applies), or as a model
  attribute to be added to the model, unless it is a simple type, as determined by
  <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-">BeanUtils#isSimpleProperty</a>,
  in which case it remains unresolved.</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect4">
<h5 id="webflux-ann-typeconversion">Type Conversion</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-typeconversion">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Some annotated controller method arguments that represent String-based request input (for example,
<code>@RequestParam</code>, <code>@RequestHeader</code>, <code>@PathVariable</code>, <code>@MatrixVariable</code>, and <code>@CookieValue</code>)
can require type conversion if the argument is declared as something other than <code>String</code>.</p>
</div>
<div class="paragraph">
<p>For such cases, type conversion is automatically applied based on the configured converters.
By default, simple types (such as <code>int</code>, <code>long</code>, <code>Date</code>, and others) are supported. Type conversion
can be customized through a <code>WebDataBinder</code> (see <a href="#webflux-ann-initbinder"><code>DataBinder</code></a>) or by registering
<code>Formatters</code> with the <code>FormattingConversionService</code> (see <a href="core.html#format">Spring Field Formatting</a>).</p>
</div>
<div class="paragraph">
<p>A practical issue in type conversion is the treatment of an empty String source value.
Such a value is treated as missing if it becomes <code>null</code> as a result of type conversion.
This can be the case for <code>Long</code>, <code>UUID</code>, and other target types. If you want to allow <code>null</code>
to be injected, either use the <code>required</code> flag on the argument annotation, or declare the
argument as <code>@Nullable</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-matrix-variables">Matrix Variables</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-matrix-variables">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><a href="https://tools.ietf.org/html/rfc3986#section-3.3">RFC 3986</a> discusses name-value pairs in
path segments. In Spring WebFlux, we refer to those as &#8220;matrix variables&#8221; based on an
<a href="https://www.w3.org/DesignIssues/MatrixURIs.html">&#8220;old post&#8221;</a> by Tim Berners-Lee, but they
can be also be referred to as URI path parameters.</p>
</div>
<div class="paragraph">
<p>Matrix variables can appear in any path segment, with each variable separated by a semicolon and
multiple values separated by commas&#8201;&#8212;&#8201;for example, <code>"/cars;color=red,green;year=2012"</code>. Multiple
values can also be specified through repeated variable names&#8201;&#8212;&#8201;for example,
<code>"color=red;color=green;color=blue"</code>.</p>
</div>
<div class="paragraph">
<p>Unlike Spring MVC, in WebFlux, the presence or absence of matrix variables in a URL does
not affect request mappings. In other words, you are not required to use a URI variable
to mask variable content. That said, if you want to access matrix variables from a
controller method, you need to add a URI variable to the path segment where matrix
variables are expected. The following example shows how to do so:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// GET /pets/42;q=11;r=22

@GetMapping("/pets/{petId}")
public void findPet(@PathVariable String petId, @MatrixVariable int q) {

    // petId == 42
    // q == 11
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// GET /pets/42;q=11;r=22

@GetMapping("/pets/{petId}")
fun findPet(@PathVariable petId: String, @MatrixVariable q: Int) {

    // petId == 42
    // q == 11
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Given that all path segments can contain matrix variables, you may sometimes need to
disambiguate which path variable the matrix variable is expected to be in,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// GET /owners/42;q=11/pets/21;q=22

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
        @MatrixVariable(name="q", pathVar="ownerId") int q1,
        @MatrixVariable(name="q", pathVar="petId") int q2) {

    // q1 == 11
    // q2 == 22
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
        @MatrixVariable(name = "q", pathVar = "ownerId") q1: Int,
        @MatrixVariable(name = "q", pathVar = "petId") q2: Int) {

    // q1 == 11
    // q2 == 22
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can define a matrix variable may be defined as optional and specify a default value
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// GET /pets/42

@GetMapping("/pets/{petId}")
public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {

    // q == 1
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// GET /pets/42

@GetMapping("/pets/{petId}")
fun findPet(@MatrixVariable(required = false, defaultValue = "1") q: Int) {

    // q == 1
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>To get all matrix variables, use a <code>MultiValueMap</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@GetMapping("/owners/{ownerId}/pets/{petId}")
public void findPet(
        @MatrixVariable MultiValueMap&lt;String, String&gt; matrixVars,
        @MatrixVariable(pathVar="petId") MultiValueMap&lt;String, String&gt; petMatrixVars) {

    // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
    // petMatrixVars: ["q" : 22, "s" : 23]
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// GET /owners/42;q=11;r=12/pets/21;q=22;s=23

@GetMapping("/owners/{ownerId}/pets/{petId}")
fun findPet(
        @MatrixVariable matrixVars: MultiValueMap&lt;String, String&gt;,
        @MatrixVariable(pathVar="petId") petMatrixVars: MultiValueMap&lt;String, String&gt;) {

    // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
    // petMatrixVars: ["q" : 22, "s" : 23]
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestparam"><code>@RequestParam</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestparam">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@RequestParam</code> annotation to bind query parameters to a method argument in a
controller. The following code snippet shows the usage:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
@RequestMapping("/pets")
public class EditPetForm {

    // ...

    @GetMapping
    public String setupForm(@RequestParam("petId") int petId, Model model) { <i class="conum" data-value="1"></i><b>(1)</b>
        Pet pet = this.clinic.loadPet(petId);
        model.addAttribute("pet", pet);
        return "petForm";
    }

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestParam</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.ui.set

@Controller
@RequestMapping("/pets")
class EditPetForm {

    // ...

    @GetMapping
    fun setupForm(@RequestParam("petId") petId: Int, model: Model): String { <i class="conum" data-value="1"></i><b>(1)</b>
        val pet = clinic.loadPet(petId)
        model["pet"] = pet
        return "petForm"
    }

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestParam</code>.</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
The Servlet API &#8220;request parameter&#8221; concept conflates query parameters, form
data, and multiparts into one. However, in WebFlux, each is accessed individually through
<code>ServerWebExchange</code>. While <code>@RequestParam</code> binds to query parameters only, you can use
data binding to apply query parameters, form data, and multiparts to a
<a href="#webflux-ann-modelattrib-method-args">command object</a>.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Method parameters that use the <code>@RequestParam</code> annotation are required by default, but
you can specify that a method parameter is optional by setting the required flag of a <code>@RequestParam</code>
to <code>false</code> or by declaring the argument with a <code>java.util.Optional</code>
wrapper.</p>
</div>
<div class="paragraph">
<p>Type conversion is applied automatically if the target method parameter type is not
<code>String</code>. See <a href="#webflux-ann-typeconversion">Type Conversion</a>.</p>
</div>
<div class="paragraph">
<p>When a <code>@RequestParam</code> annotation is declared on a <code>Map&lt;String, String&gt;</code> or
<code>MultiValueMap&lt;String, String&gt;</code> argument, the map is populated with all query parameters.</p>
</div>
<div class="paragraph">
<p>Note that use of <code>@RequestParam</code> is optional&#8201;&#8212;&#8201;for example, to set its attributes. By
default, any argument that is a simple value type (as determined by
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-">BeanUtils#isSimpleProperty</a>)
and is not resolved by any other argument resolver is treated as if it were annotated
with <code>@RequestParam</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestheader"><code>@RequestHeader</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestheader">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@RequestHeader</code> annotation to bind a request header to a method argument in a
controller.</p>
</div>
<div class="paragraph">
<p>The following example shows a request with headers:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>Host                    localhost:8080
Accept                  text/html,application/xhtml+xml,application/xml;q=0.9
Accept-Language         fr,en-gb;q=0.7,en;q=0.3
Accept-Encoding         gzip,deflate
Accept-Charset          ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive              300</pre>
</div>
</div>
<div class="paragraph">
<p>The following example gets the value of the <code>Accept-Encoding</code> and <code>Keep-Alive</code> headers:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/demo")
public void handle(
        @RequestHeader("Accept-Encoding") String encoding, <i class="conum" data-value="1"></i><b>(1)</b>
        @RequestHeader("Keep-Alive") long keepAlive) { <i class="conum" data-value="2"></i><b>(2)</b>
    //...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Get the value of the <code>Accept-Encoging</code> header.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Get the value of the <code>Keep-Alive</code> header.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/demo")
fun handle(
        @RequestHeader("Accept-Encoding") encoding: String, <i class="conum" data-value="1"></i><b>(1)</b>
        @RequestHeader("Keep-Alive") keepAlive: Long) { <i class="conum" data-value="2"></i><b>(2)</b>
    //...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Get the value of the <code>Accept-Encoging</code> header.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Get the value of the <code>Keep-Alive</code> header.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Type conversion is applied automatically if the target method parameter type is not
<code>String</code>. See <a href="#webflux-ann-typeconversion">Type Conversion</a>.</p>
</div>
<div class="paragraph">
<p>When a <code>@RequestHeader</code> annotation is used on a <code>Map&lt;String, String&gt;</code>,
<code>MultiValueMap&lt;String, String&gt;</code>, or <code>HttpHeaders</code> argument, the map is populated
with all header values.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
Built-in support is available for converting a comma-separated string into an
array or collection of strings or other types known to the type conversion system. For
example, a method parameter annotated with <code>@RequestHeader("Accept")</code> may be of type
<code>String</code> but also of <code>String[]</code> or <code>List&lt;String&gt;</code>.
</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-cookievalue"><code>@CookieValue</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-cookievalue">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@CookieValue</code> annotation to bind the value of an HTTP cookie to a method argument
in a controller.</p>
</div>
<div class="paragraph">
<p>The following example shows a request with a cookie:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>JSESSIONID=415A4AC178C59DACE0B2C9CA727CDD84</pre>
</div>
</div>
<div class="paragraph">
<p>The following code sample demonstrates how to get the cookie value:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/demo")
public void handle(@CookieValue("JSESSIONID") String cookie) { <i class="conum" data-value="1"></i><b>(1)</b>
    //...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Get the cookie value.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/demo")
fun handle(@CookieValue("JSESSIONID") cookie: String) { <i class="conum" data-value="1"></i><b>(1)</b>
    //...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Get the cookie value.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Type conversion is applied automatically if the target method parameter type is not
<code>String</code>. See <a href="#webflux-ann-typeconversion">Type Conversion</a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-modelattrib-method-args"><code>@ModelAttribute</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-modelattrib-method-args">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@ModelAttribute</code> annotation on a method argument to access an attribute from the
model or have it instantiated if not present. The model attribute is also overlain with
the values of query parameters and form fields whose names match to field names. This is
referred to as data binding, and it saves you from having to deal with parsing and
converting individual query parameters and form fields. The following example binds an instance of <code>Pet</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute Pet pet) { } <i class="conum" data-value="1"></i><b>(1)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Bind an instance of <code>Pet</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { } <i class="conum" data-value="1"></i><b>(1)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Bind an instance of <code>Pet</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>Pet</code> instance in the preceding example is resolved as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>From the model if already added through <a href="#webflux-ann-modelattrib-methods"><code>Model</code></a>.</p>
</li>
<li>
<p>From the HTTP session through <a href="#webflux-ann-sessionattributes"><code>@SessionAttributes</code></a>.</p>
</li>
<li>
<p>From the invocation of a default constructor.</p>
</li>
<li>
<p>From the invocation of a &#8220;primary constructor&#8221; with arguments that match query
parameters or form fields. Argument names are determined through JavaBeans
<code>@ConstructorProperties</code> or through runtime-retained parameter names in the bytecode.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>After the model attribute instance is obtained, data binding is applied. The
<code>WebExchangeDataBinder</code> class matches names of query parameters and form fields to field
names on the target <code>Object</code>. Matching fields are populated after type conversion is applied
where necessary. For more on data binding (and validation), see
<a href="core.html#validation">Validation</a>. For more on customizing data binding, see
<a href="#webflux-ann-initbinder"><code>DataBinder</code></a>.</p>
</div>
<div class="paragraph">
<p>Data binding can result in errors. By default, a <code>WebExchangeBindException</code> is raised, but,
to check for such errors in the controller method, you can add a <code>BindingResult</code> argument
immediately next to the <code>@ModelAttribute</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { <i class="conum" data-value="1"></i><b>(1)</b>
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Adding a <code>BindingResult</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { <i class="conum" data-value="1"></i><b>(1)</b>
    if (result.hasErrors()) {
        return "petForm"
    }
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Adding a <code>BindingResult</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You can automatically apply validation after data binding by adding the
<code>javax.validation.Valid</code> annotation or Spring&#8217;s <code>@Validated</code> annotation (see also
<a href="core.html#validation-beanvalidation">Bean Validation</a> and
<a href="core.html#validation">Spring validation</a>). The following example uses the <code>@Valid</code> annotation:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { <i class="conum" data-value="1"></i><b>(1)</b>
    if (result.hasErrors()) {
        return "petForm";
    }
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@Valid</code> on a model attribute argument.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { <i class="conum" data-value="1"></i><b>(1)</b>
    if (result.hasErrors()) {
        return "petForm"
    }
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@Valid</code> on a model attribute argument.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Spring WebFlux, unlike Spring MVC, supports reactive types in the model&#8201;&#8212;&#8201;for example,
<code>Mono&lt;Account&gt;</code> or <code>io.reactivex.Single&lt;Account&gt;</code>. You can declare a <code>@ModelAttribute</code> argument
with or without a reactive type wrapper, and it will be resolved accordingly,
to the actual value if necessary. However, note that, to use a <code>BindingResult</code>
argument, you must declare the <code>@ModelAttribute</code> argument before it without a reactive
type wrapper, as shown earlier. Alternatively, you can handle any errors through the
reactive type, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
public Mono&lt;String&gt; processSubmit(@Valid @ModelAttribute("pet") Mono&lt;Pet&gt; petMono) {
    return petMono
        .flatMap(pet -&gt; {
            // ...
        })
        .onErrorResume(ex -&gt; {
            // ...
        });
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@Valid @ModelAttribute("pet") petMono: Mono&lt;Pet&gt;): Mono&lt;String&gt; {
    return petMono
            .flatMap { pet -&gt;
                // ...
            }
            .onErrorResume{ ex -&gt;
                // ...
            }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that use of <code>@ModelAttribute</code> is optional&#8201;&#8212;&#8201;for example, to set its attributes.
By default, any argument that is not a simple value type( as determined by
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-">BeanUtils#isSimpleProperty</a>)
and is not resolved by any other argument resolver is treated as if it were annotated
with <code>@ModelAttribute</code>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-sessionattributes"><code>@SessionAttributes</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-sessionattributes">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>@SessionAttributes</code> is used to store model attributes in the <code>WebSession</code> between
requests. It is a type-level annotation that declares session attributes used by a
specific controller. This typically lists the names of model attributes or types of
model attributes that should be transparently stored in the session for subsequent
requests to access.</p>
</div>
<div class="paragraph">
<p>Consider the following example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
@SessionAttributes("pet") <i class="conum" data-value="1"></i><b>(1)</b>
public class EditPetForm {
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using the <code>@SessionAttributes</code> annotation.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
@SessionAttributes("pet") <i class="conum" data-value="1"></i><b>(1)</b>
class EditPetForm {
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using the <code>@SessionAttributes</code> annotation.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>On the first request, when a model attribute with the name, <code>pet</code>, is added to the model,
it is automatically promoted to and saved in the <code>WebSession</code>. It remains there until
another controller method uses a <code>SessionStatus</code> method argument to clear the storage,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
@SessionAttributes("pet") <i class="conum" data-value="1"></i><b>(1)</b>
public class EditPetForm {

    // ...

    @PostMapping("/pets/{id}")
    public String handle(Pet pet, BindingResult errors, SessionStatus status) { <i class="conum" data-value="2"></i><b>(2)</b>
        if (errors.hasErrors()) {
            // ...
        }
            status.setComplete();
            // ...
        }
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using the <code>@SessionAttributes</code> annotation.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using a <code>SessionStatus</code> variable.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
@SessionAttributes("pet") <i class="conum" data-value="1"></i><b>(1)</b>
class EditPetForm {

    // ...

    @PostMapping("/pets/{id}")
    fun handle(pet: Pet, errors: BindingResult, status: SessionStatus): String { <i class="conum" data-value="2"></i><b>(2)</b>
        if (errors.hasErrors()) {
            // ...
        }
        status.setComplete()
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using the <code>@SessionAttributes</code> annotation.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using a <code>SessionStatus</code> variable.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-sessionattribute"><code>@SessionAttribute</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-sessionattribute">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>If you need access to pre-existing session attributes that are managed globally
(that is, outside the controller&#8201;&#8212;&#8201;for example, by a filter) and may or may not be present,
you can use the <code>@SessionAttribute</code> annotation on a method parameter, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/")
public String handle(@SessionAttribute User user) { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@SessionAttribute</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/")
fun handle(@SessionAttribute user: User): String { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@SessionAttribute</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For use cases that require adding or removing session attributes, consider injecting
<code>WebSession</code> into the controller method.</p>
</div>
<div class="paragraph">
<p>For temporary storage of model attributes in the session as part of a controller
workflow, consider using <code>SessionAttributes</code>, as described in
<a href="#webflux-ann-sessionattributes"><code>@SessionAttributes</code></a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestattrib"><code>@RequestAttribute</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestattrib">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Similarly to <code>@SessionAttribute</code>, you can use the <code>@RequestAttribute</code> annotation to
access pre-existing request attributes created earlier (for example, by a <code>WebFilter</code>),
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/")
public String handle(@RequestAttribute Client client) { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestAttribute</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/")
fun handle(@RequestAttribute client: Client): String { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestAttribute</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-multipart-forms">Multipart Content</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-multipart-forms">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>As explained in <a href="#webflux-multipart">Multipart Data</a>, <code>ServerWebExchange</code> provides access to multipart
content. The best way to handle a file upload form (for example, from a browser) in a controller
is through data binding to a <a href="#webflux-ann-modelattrib-method-args">command object</a>,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">class MyForm {

    private String name;

    private MultipartFile file;

    // ...

}

@Controller
public class FileUploadController {

    @PostMapping("/form")
    public String handleFormUpload(MyForm form, BindingResult errors) {
        // ...
    }

}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">class MyForm(
        val name: String,
        val file: MultipartFile)

@Controller
class FileUploadController {

    @PostMapping("/form")
    fun handleFormUpload(form: MyForm, errors: BindingResult): String {
        // ...
    }

}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can also submit multipart requests from non-browser clients in a RESTful service
scenario. The following example uses a file along with JSON:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>POST /someUrl
Content-Type: multipart/mixed

--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="meta-data"
Content-Type: application/json; charset=UTF-8
Content-Transfer-Encoding: 8bit

{
    "name": "value"
}
--edt7Tfrdusa7r3lNQc79vXuhIIMlatb7PQg7Vp
Content-Disposition: form-data; name="file-data"; filename="file.properties"
Content-Type: text/xml
Content-Transfer-Encoding: 8bit
... File Data ...</pre>
</div>
</div>
<div class="paragraph">
<p>You can access individual parts with <code>@RequestPart</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/")
public String handle(@RequestPart("meta-data") Part metadata, <i class="conum" data-value="1"></i><b>(1)</b>
        @RequestPart("file-data") FilePart file) { <i class="conum" data-value="2"></i><b>(2)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestPart</code> to get the metadata.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using <code>@RequestPart</code> to get the file.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/")
fun handle(@RequestPart("meta-data") Part metadata, <i class="conum" data-value="1"></i><b>(1)</b>
        @RequestPart("file-data") FilePart file): String { <i class="conum" data-value="2"></i><b>(2)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestPart</code> to get the metadata.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using <code>@RequestPart</code> to get the file.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To deserialize the raw part content (for example, to JSON&#8201;&#8212;&#8201;similar to <code>@RequestBody</code>),
you can declare a concrete target <code>Object</code>, instead of <code>Part</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/")
public String handle(@RequestPart("meta-data") MetaData metadata) { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestPart</code> to get the metadata.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/")
fun handle(@RequestPart("meta-data") metadata: MetaData): String { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestPart</code> to get the metadata.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You can use <code>@RequestPart</code> in combination with <code>javax.validation.Valid</code> or Spring&#8217;s
<code>@Validated</code> annotation, which causes Standard Bean Validation to be applied. Validation
errors lead to a <code>WebExchangeBindException</code> that results in a 400 (BAD_REQUEST) response.
The exception contains a <code>BindingResult</code> with the error details and can also be handled
in the controller method by declaring the argument with an async wrapper and then using
error related operators:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/")
public String handle(@Valid @RequestPart("meta-data") Mono&lt;MetaData&gt; metadata) {
    // use one of the onError* operators...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/")
fun handle(@Valid @RequestPart("meta-data") metadata: MetaData): String {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>To access all multipart data as a <code>MultiValueMap</code>, you can use <code>@RequestBody</code>,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/")
public String handle(@RequestBody Mono&lt;MultiValueMap&lt;String, Part&gt;&gt; parts) { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestBody</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/")
fun handle(@RequestBody parts: MultiValueMap&lt;String, Part&gt;): String { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestBody</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To access multipart data sequentially, in streaming fashion, you can use <code>@RequestBody</code> with
<code>Flux&lt;Part&gt;</code> (or <code>Flow&lt;Part&gt;</code> in Kotlin) instead, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/")
public String handle(@RequestBody Flux&lt;Part&gt; parts) { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestBody</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/")
fun handle(@RequestBody parts: Flow&lt;Part&gt;): String { <i class="conum" data-value="1"></i><b>(1)</b>
    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@RequestBody</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-requestbody"><code>@RequestBody</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-requestbody">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@RequestBody</code> annotation to have the request body read and deserialized into an
<code>Object</code> through an <a href="#webflux-codecs">HttpMessageReader</a>.
The following example uses a <code>@RequestBody</code> argument:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/accounts")
public void handle(@RequestBody Account account) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/accounts")
fun handle(@RequestBody account: Account) {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Unlike Spring MVC, in WebFlux, the <code>@RequestBody</code> method argument supports reactive types
and fully non-blocking reading and (client-to-server) streaming.</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/accounts")
public void handle(@RequestBody Mono&lt;Account&gt; account) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/accounts")
fun handle(@RequestBody accounts: Flow&lt;Account&gt;) {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can use the <a href="#webflux-config-message-codecs">HTTP message codecs</a> option of the <a href="#webflux-config">WebFlux Config</a> to
configure or customize message readers.</p>
</div>
<div class="paragraph">
<p>You can use <code>@RequestBody</code> in combination with <code>javax.validation.Valid</code> or Spring&#8217;s
<code>@Validated</code> annotation, which causes Standard Bean Validation to be applied. Validation
errors cause a <code>WebExchangeBindException</code>, which results in a 400 (BAD_REQUEST) response.
The exception contains a <code>BindingResult</code> with error details and can be handled in the
controller method by declaring the argument with an async wrapper and then using error
related operators:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/accounts")
public void handle(@Valid @RequestBody Mono&lt;Account&gt; account) {
    // use one of the onError* operators...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/accounts")
fun handle(@Valid @RequestBody account: Mono&lt;Account&gt;) {
    // ...
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-httpentity"><code>HttpEntity</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-httpentity">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>HttpEntity</code> is more or less identical to using <a href="#webflux-ann-requestbody"><code>@RequestBody</code></a> but is based on a
container object that exposes request headers and the body. The following example uses an
<code>HttpEntity</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@PostMapping("/accounts")
public void handle(HttpEntity&lt;Account&gt; entity) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@PostMapping("/accounts")
fun handle(entity: HttpEntity&lt;Account&gt;) {
    // ...
}</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-responsebody"><code>@ResponseBody</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-responsebody">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@ResponseBody</code> annotation on a method to have the return serialized
to the response body through an <a href="#webflux-codecs">HttpMessageWriter</a>. The following
example shows how to do so:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/accounts/{id}")
@ResponseBody
public Account handle() {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/accounts/{id}")
@ResponseBody
fun handle(): Account {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>@ResponseBody</code> is also supported at the class level, in which case it is inherited by
all controller methods. This is the effect of <code>@RestController</code>, which is nothing more
than a meta-annotation marked with <code>@Controller</code> and <code>@ResponseBody</code>.</p>
</div>
<div class="paragraph">
<p><code>@ResponseBody</code> supports reactive types, which means you can return Reactor or RxJava
types and have the asynchronous values they produce rendered to the response.
For additional details, see <a href="#webflux-codecs-streaming">Streaming</a> and
<a href="#webflux-codecs-jackson">JSON rendering</a>.</p>
</div>
<div class="paragraph">
<p>You can combine <code>@ResponseBody</code> methods with JSON serialization views.
See <a href="#webflux-ann-jackson">Jackson JSON</a> for details.</p>
</div>
<div class="paragraph">
<p>You can use the <a href="#webflux-config-message-codecs">HTTP message codecs</a> option of the <a href="#webflux-config">WebFlux Config</a> to
configure or customize message writing.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-responseentity"><code>ResponseEntity</code></h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-responseentity">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>ResponseEntity</code> is like <a href="#webflux-ann-responsebody"><code>@ResponseBody</code></a> but with status and headers. For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/something")
public ResponseEntity&lt;String&gt; handle() {
    String body = ... ;
    String etag = ... ;
    return ResponseEntity.ok().eTag(etag).build(body);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/something")
fun handle(): ResponseEntity&lt;String&gt; {
    val body: String = ...
    val etag: String = ...
    return ResponseEntity.ok().eTag(etag).build(body)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>WebFlux supports using a single value <a href="#webflux-reactive-libraries">reactive type</a> to
produce the <code>ResponseEntity</code> asynchronously, and/or single and multi-value reactive types
for the body. This allows a variety of async responses with <code>ResponseEntity</code> as follows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>ResponseEntity&lt;Mono&lt;T&gt;&gt;</code> or <code>ResponseEntity&lt;Flux&lt;T&gt;&gt;</code> make the response status and
headers known immediately while the body is provided asynchronously at a later point.
Use <code>Mono</code> if the body consists of 0..1 values or <code>Flux</code> if it can produce multiple values.</p>
</li>
<li>
<p><code>Mono&lt;ResponseEntity&lt;T&gt;&gt;</code> provides all three&#8201;&#8212;&#8201;response status, headers, and body,
asynchronously at a later point. This allows the response status and headers to vary
depending on the outcome of asynchronous request handling.</p>
</li>
<li>
<p><code>Mono&lt;ResponseEntity&lt;Mono&lt;T&gt;&gt;&gt;</code> or <code>Mono&lt;ResponseEntity&lt;Flux&lt;T&gt;&gt;&gt;</code> are yet another
possible, albeit less common alternative. They provide the response status and headers
asynchronously first and then the response body, also asynchronously, second.</p>
</li>
</ul>
</div>
</div>
<div class="sect4">
<h5 id="webflux-ann-jackson">Jackson JSON</h5>
<div class="paragraph">
<p>Spring offers support for the Jackson JSON library.</p>
</div>
<div class="sect5">
<h6 id="webflux-ann-jsonview">JSON Views</h6>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-jackson">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux provides built-in support for
<a href="https://www.baeldung.com/jackson-json-view-annotation">Jackson&#8217;s Serialization Views</a>,
which allows rendering only a subset of all fields in an <code>Object</code>. To use it with
<code>@ResponseBody</code> or <code>ResponseEntity</code> controller methods, you can use Jackson&#8217;s
<code>@JsonView</code> annotation to activate a serialization view class, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@RestController
public class UserController {

    @GetMapping("/user")
    @JsonView(User.WithoutPasswordView.class)
    public User getUser() {
        return new User("eric", "7!jd#h23");
    }
}

public class User {

    public interface WithoutPasswordView {};
    public interface WithPasswordView extends WithoutPasswordView {};

    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @JsonView(WithoutPasswordView.class)
    public String getUsername() {
        return this.username;
    }

    @JsonView(WithPasswordView.class)
    public String getPassword() {
        return this.password;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@RestController
class UserController {

    @GetMapping("/user")
    @JsonView(User.WithoutPasswordView::class)
    fun getUser(): User {
        return User("eric", "7!jd#h23")
    }
}

class User(
        @JsonView(WithoutPasswordView::class) val username: String,
        @JsonView(WithPasswordView::class) val password: String
) {
    interface WithoutPasswordView
    interface WithPasswordView : WithoutPasswordView
}</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<code>@JsonView</code> allows an array of view classes but you can only specify only one per
controller method. Use a composite interface if you need to activate multiple views.
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-ann-modelattrib-methods">1.4.4. <code>Model</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-modelattrib-methods">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@ModelAttribute</code> annotation:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>On a <a href="#webflux-ann-modelattrib-method-args">method argument</a> in <code>@RequestMapping</code> methods
to create or access an Object from the model and to bind it to the request through a
<code>WebDataBinder</code>.</p>
</li>
<li>
<p>As a method-level annotation in <code>@Controller</code> or <code>@ControllerAdvice</code> classes, helping
to initialize the model prior to any <code>@RequestMapping</code> method invocation.</p>
</li>
<li>
<p>On a <code>@RequestMapping</code> method to mark its return value as a model attribute.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>This section discusses <code>@ModelAttribute</code> methods, or the second item from the preceding list.
A controller can have any number of <code>@ModelAttribute</code> methods. All such methods are
invoked before <code>@RequestMapping</code> methods in the same controller. A <code>@ModelAttribute</code>
method can also be shared across controllers through <code>@ControllerAdvice</code>. See the section on
<a href="#webflux-ann-controller-advice">Controller Advice</a> for more details.</p>
</div>
<div class="paragraph">
<p><code>@ModelAttribute</code> methods have flexible method signatures. They support many of the same
arguments as <code>@RequestMapping</code> methods (except for <code>@ModelAttribute</code> itself and anything
related to the request body).</p>
</div>
<div class="paragraph">
<p>The following example uses a <code>@ModelAttribute</code> method:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@ModelAttribute
public void populateModel(@RequestParam String number, Model model) {
    model.addAttribute(accountRepository.findAccount(number));
    // add more ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@ModelAttribute
fun populateModel(@RequestParam number: String, model: Model) {
    model.addAttribute(accountRepository.findAccount(number))
    // add more ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example adds one attribute only:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@ModelAttribute
public Account addAccount(@RequestParam String number) {
    return accountRepository.findAccount(number);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@ModelAttribute
fun addAccount(@RequestParam number: String): Account {
    return accountRepository.findAccount(number);
}</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
When a name is not explicitly specified, a default name is chosen based on the type,
as explained in the javadoc for <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/Conventions.html"><code>Conventions</code></a>.
You can always assign an explicit name by using the overloaded <code>addAttribute</code> method or
through the name attribute on <code>@ModelAttribute</code> (for a return value).
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Spring WebFlux, unlike Spring MVC, explicitly supports reactive types in the model
(for example, <code>Mono&lt;Account&gt;</code> or <code>io.reactivex.Single&lt;Account&gt;</code>). Such asynchronous model
attributes can be transparently resolved (and the model updated) to their actual values
at the time of <code>@RequestMapping</code> invocation, provided a <code>@ModelAttribute</code> argument is
declared without a wrapper, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@ModelAttribute
public void addAccount(@RequestParam String number) {
    Mono&lt;Account&gt; accountMono = accountRepository.findAccount(number);
    model.addAttribute("account", accountMono);
}

@PostMapping("/accounts")
public String handle(@ModelAttribute Account account, BindingResult errors) {
    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.ui.set

@ModelAttribute
fun addAccount(@RequestParam number: String) {
    val accountMono: Mono&lt;Account&gt; = accountRepository.findAccount(number)
    model["account"] = accountMono
}

@PostMapping("/accounts")
fun handle(@ModelAttribute account: Account, errors: BindingResult): String {
    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition, any model attributes that have a reactive type wrapper are resolved to their
actual values (and the model updated) just prior to view rendering.</p>
</div>
<div class="paragraph">
<p>You can also use <code>@ModelAttribute</code> as a method-level annotation on <code>@RequestMapping</code>
methods, in which case the return value of the <code>@RequestMapping</code> method is interpreted as a
model attribute. This is typically not required, as it is the default behavior in HTML
controllers, unless the return value is a <code>String</code> that would otherwise be interpreted
as a view name. <code>@ModelAttribute</code> can also help to customize the model attribute name,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
public Account handle() {
    // ...
    return account;
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/accounts/{id}")
@ModelAttribute("myAccount")
fun handle(): Account {
    // ...
    return account
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-ann-initbinder">1.4.5. <code>DataBinder</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-initbinder">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>@Controller</code> or <code>@ControllerAdvice</code> classes can have <code>@InitBinder</code> methods, to
initialize instances of <code>WebDataBinder</code>. Those, in turn, are used to:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Bind request parameters (that is, form data or query) to a model object.</p>
</li>
<li>
<p>Convert <code>String</code>-based request values (such as request parameters, path variables,
headers, cookies, and others) to the target type of controller method arguments.</p>
</li>
<li>
<p>Format model object values as <code>String</code> values when rendering HTML forms.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>@InitBinder</code> methods can register controller-specific <code>java.beans.PropertyEditor</code> or
Spring <code>Converter</code> and <code>Formatter</code> components. In addition, you can use the
<a href="#webflux-config-conversion">WebFlux Java configuration</a> to register <code>Converter</code> and
<code>Formatter</code> types in a globally shared <code>FormattingConversionService</code>.</p>
</div>
<div class="paragraph">
<p><code>@InitBinder</code> methods support many of the same arguments that <code>@RequestMapping</code> methods
do, except for <code>@ModelAttribute</code> (command object) arguments. Typically, they are declared
with a <code>WebDataBinder</code> argument, for registrations, and a <code>void</code> return value.
The following example uses the <code>@InitBinder</code> annotation:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
public class FormController {

    @InitBinder <i class="conum" data-value="1"></i><b>(1)</b>
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using the <code>@InitBinder</code> annotation.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
class FormController {

    @InitBinder <i class="conum" data-value="1"></i><b>(1)</b>
    fun initBinder(binder: WebDataBinder) {
        val dateFormat = SimpleDateFormat("yyyy-MM-dd")
        dateFormat.isLenient = false
        binder.registerCustomEditor(Date::class.java, CustomDateEditor(dateFormat, false))
    }

    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, when using a <code>Formatter</code>-based setup through a shared
<code>FormattingConversionService</code>, you could re-use the same approach and register
controller-specific <code>Formatter</code> instances, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
public class FormController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd")); <i class="conum" data-value="1"></i><b>(1)</b>
    }

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Adding a custom formatter (a <code>DateFormatter</code>, in this case).</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
class FormController {

    @InitBinder
    fun initBinder(binder: WebDataBinder) {
        binder.addCustomFormatter(DateFormatter("yyyy-MM-dd")) <i class="conum" data-value="1"></i><b>(1)</b>
    }

    // ...
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Adding a custom formatter (a <code>DateFormatter</code>, in this case).</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-ann-controller-exceptions">1.4.6. Managing Exceptions</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-exceptionhandler">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>@Controller</code> and <a href="#webflux-ann-controller-advice">@ControllerAdvice</a> classes can have
<code>@ExceptionHandler</code> methods to handle exceptions from controller methods. The following
example includes such a handler method:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
public class SimpleController {

    // ...

    @ExceptionHandler <i class="conum" data-value="1"></i><b>(1)</b>
    public ResponseEntity&lt;String&gt; handle(IOException ex) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Declaring an <code>@ExceptionHandler</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
class SimpleController {

    // ...

    @ExceptionHandler <i class="conum" data-value="1"></i><b>(1)</b>
    fun handle(ex: IOException): ResponseEntity&lt;String&gt; {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Declaring an <code>@ExceptionHandler</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The exception can match against a top-level exception being propagated (that is, a direct
<code>IOException</code> being thrown) or against the immediate cause within a top-level wrapper
exception (for example, an <code>IOException</code> wrapped inside an <code>IllegalStateException</code>).</p>
</div>
<div class="paragraph">
<p>For matching exception types, preferably declare the target exception as a method argument,
as shown in the preceding example. Alternatively, the annotation declaration can narrow the
exception types to match. We generally recommend being as specific as possible in the
argument signature and to declare your primary root exception mappings on a
<code>@ControllerAdvice</code> prioritized with a corresponding order.
See <a href="web.html#mvc-ann-exceptionhandler">the MVC section</a> for details.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
An <code>@ExceptionHandler</code> method in WebFlux supports the same method arguments and
return values as a <code>@RequestMapping</code> method, with the exception of request body-
and <code>@ModelAttribute</code>-related method arguments.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Support for <code>@ExceptionHandler</code> methods in Spring WebFlux is provided by the
<code>HandlerAdapter</code> for <code>@RequestMapping</code> methods. See <a href="#webflux-dispatcher-handler"><code>DispatcherHandler</code></a>
for more detail.</p>
</div>
<div class="sect4">
<h5 id="webflux-ann-rest-exceptions">REST API exceptions</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-rest-exceptions">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>A common requirement for REST services is to include error details in the body of the
response. The Spring Framework does not automatically do so, because the representation
of error details in the response body is application-specific. However, a
<code>@RestController</code> can use <code>@ExceptionHandler</code> methods with a <code>ResponseEntity</code> return
value to set the status and the body of the response. Such methods can also be declared
in <code>@ControllerAdvice</code> classes to apply them globally.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Note that Spring WebFlux does not have an equivalent for the Spring MVC
<code>ResponseEntityExceptionHandler</code>, because WebFlux raises only <code>ResponseStatusException</code>
(or subclasses thereof), and those do not need to be translated to
an HTTP status code.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-ann-controller-advice">1.4.7. Controller Advice</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-ann-controller-advice">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Typically, the <code>@ExceptionHandler</code>, <code>@InitBinder</code>, and <code>@ModelAttribute</code> methods apply
within the <code>@Controller</code> class (or class hierarchy) in which they are declared. If you
want such methods to apply more globally (across controllers), you can declare them in a
class annotated with <code>@ControllerAdvice</code> or <code>@RestControllerAdvice</code>.</p>
</div>
<div class="paragraph">
<p><code>@ControllerAdvice</code> is annotated with <code>@Component</code>, which means that such classes can be
registered as Spring beans through <a href="core.html#beans-java-instantiating-container-scan">component scanning</a>. <code>@RestControllerAdvice</code> is a composed annotation that is annotated
with both <code>@ControllerAdvice</code> and <code>@ResponseBody</code>, which essentially means
<code>@ExceptionHandler</code> methods are rendered to the response body through message conversion
(versus view resolution or template rendering).</p>
</div>
<div class="paragraph">
<p>On startup, the infrastructure classes for <code>@RequestMapping</code> and <code>@ExceptionHandler</code>
methods detect Spring beans annotated with <code>@ControllerAdvice</code> and then apply their
methods at runtime. Global <code>@ExceptionHandler</code> methods (from a <code>@ControllerAdvice</code>) are
applied <em>after</em> local ones (from the <code>@Controller</code>). By contrast, global <code>@ModelAttribute</code>
and <code>@InitBinder</code> methods are applied <em>before</em> local ones.</p>
</div>
<div class="paragraph">
<p>By default, <code>@ControllerAdvice</code> methods apply to every request (that is, all controllers),
but you can narrow that down to a subset of controllers by using attributes on the
annotation, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}

// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// Target all Controllers annotated with @RestController
@ControllerAdvice(annotations = [RestController::class])
public class ExampleAdvice1 {}

// Target all Controllers within specific packages
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

// Target all Controllers assignable to specific classes
@ControllerAdvice(assignableTypes = [ControllerInterface::class, AbstractController::class])
public class ExampleAdvice3 {}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The selectors in the preceding example are evaluated at runtime and may negatively impact
performance if used extensively. See the
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html"><code>@ControllerAdvice</code></a>
javadoc for more details.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-fn">1.5. Functional Endpoints</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#webmvc-fn">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux includes WebFlux.fn, a lightweight functional programming model in which functions
are used to route and handle requests and contracts are designed for immutability.
It is an alternative to the annotation-based programming model but otherwise runs on
the same <a href="web-reactive.html#webflux-reactive-spring-web">web-reactive.html</a> foundation.</p>
</div>
<div class="sect3">
<h4 id="webflux-fn-overview">1.5.1. Overview</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#webmvc-fn-overview">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>In WebFlux.fn, an HTTP request is handled with a <code>HandlerFunction</code>: a function that takes
<code>ServerRequest</code> and returns a delayed <code>ServerResponse</code> (i.e. <code>Mono&lt;ServerResponse&gt;</code>).
Both the request and the response object have immutable contracts that offer JDK 8-friendly
access to the HTTP request and response.
<code>HandlerFunction</code> is the equivalent of the body of a <code>@RequestMapping</code> method in the
annotation-based programming model.</p>
</div>
<div class="paragraph">
<p>Incoming requests are routed to a handler function with a <code>RouterFunction</code>: a function that
takes <code>ServerRequest</code> and returns a delayed <code>HandlerFunction</code> (i.e. <code>Mono&lt;HandlerFunction&gt;</code>).
When the router function matches, a handler function is returned; otherwise an empty Mono.
<code>RouterFunction</code> is the equivalent of a <code>@RequestMapping</code> annotation, but with the major
difference that router functions provide not just data, but also behavior.</p>
</div>
<div class="paragraph">
<p><code>RouterFunctions.route()</code> provides a router builder that facilitates the creation of routers,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;

PersonRepository repository = ...
PersonHandler handler = new PersonHandler(repository);

RouterFunction&lt;ServerResponse&gt; route = route()
    .GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson)
    .GET("/person", accept(APPLICATION_JSON), handler::listPeople)
    .POST("/person", handler::createPerson)
    .build();


public class PersonHandler {

    // ...

    public Mono&lt;ServerResponse&gt; listPeople(ServerRequest request) {
        // ...
    }

    public Mono&lt;ServerResponse&gt; createPerson(ServerRequest request) {
        // ...
    }

    public Mono&lt;ServerResponse&gt; getPerson(ServerRequest request) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val repository: PersonRepository = ...
val handler = PersonHandler(repository)

val route = coRouter { <i class="conum" data-value="1"></i><b>(1)</b>
    accept(APPLICATION_JSON).nest {
        GET("/person/{id}", handler::getPerson)
        GET("/person", handler::listPeople)
    }
    POST("/person", handler::createPerson)
}


class PersonHandler(private val repository: PersonRepository) {

    // ...

    suspend fun listPeople(request: ServerRequest): ServerResponse {
        // ...
    }

    suspend fun createPerson(request: ServerRequest): ServerResponse {
        // ...
    }

    suspend fun getPerson(request: ServerRequest): ServerResponse {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Create router using Coroutines router DSL, a Reactive alternative is also available via <code>router { }</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>One way to run a <code>RouterFunction</code> is to turn it into an <code>HttpHandler</code> and install it
through one of the built-in <a href="web-reactive.html#webflux-httphandler">server adapters</a>:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>RouterFunctions.toHttpHandler(RouterFunction)</code></p>
</li>
<li>
<p><code>RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Most applications can run through the WebFlux Java configuration, see <a href="#webflux-fn-running">Running a Server</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-fn-handler-functions">1.5.2. HandlerFunction</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#webmvc-fn-handler-functions">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>ServerRequest</code> and <code>ServerResponse</code> are immutable interfaces that offer JDK 8-friendly
access to the HTTP request and response.
Both request and response provide <a href="https://www.reactive-streams.org">Reactive Streams</a> back pressure
against the body streams.
The request body is represented with a Reactor <code>Flux</code> or <code>Mono</code>.
The response body is represented with any Reactive Streams <code>Publisher</code>, including <code>Flux</code> and <code>Mono</code>.
For more on that, see <a href="web-reactive.html#webflux-reactive-libraries">Reactive Libraries</a>.</p>
</div>
<div class="sect4">
<h5 id="webflux-fn-request">ServerRequest</h5>
<div class="paragraph">
<p><code>ServerRequest</code> provides access to the HTTP method, URI, headers, and query parameters,
while access to the body is provided through the <code>body</code> methods.</p>
</div>
<div class="paragraph">
<p>The following example extracts the request body to a <code>Mono&lt;String&gt;</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;String&gt; string = request.bodyToMono(String.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val string = request.awaitBody&lt;String&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example extracts the body to a <code>Flux&lt;Person&gt;</code> (or a <code>Flow&lt;Person&gt;</code> in Kotlin),
where <code>Person</code> objects are decoded from someserialized form, such as JSON or XML:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Flux&lt;Person&gt; people = request.bodyToFlux(Person.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val people = request.bodyToFlow&lt;Person&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The preceding examples are shortcuts that use the more general <code>ServerRequest.body(BodyExtractor)</code>,
which accepts the <code>BodyExtractor</code> functional strategy interface. The utility class
<code>BodyExtractors</code> provides access to a number of instances. For example, the preceding examples can
also be written as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;String&gt; string = request.body(BodyExtractors.toMono(String.class));
Flux&lt;Person&gt; people = request.body(BodyExtractors.toFlux(Person.class));</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">    val string = request.body(BodyExtractors.toMono(String::class.java)).awaitSingle()
    val people = request.body(BodyExtractors.toFlux(Person::class.java)).asFlow()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example shows how to access form data:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;MultiValueMap&lt;String, String&gt; map = request.formData();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val map = request.awaitFormData()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example shows how to access multipart data as a map:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;MultiValueMap&lt;String, Part&gt; map = request.multipartData();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val map = request.awaitMultipartData()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example shows how to access multiparts, one at a time, in streaming fashion:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Flux&lt;Part&gt; parts = request.body(BodyExtractors.toParts());</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val parts = request.body(BodyExtractors.toParts()).asFlow()</code></pre>
</div>
</div>
</div>
<div class="sect4">
<h5 id="webflux-fn-response">ServerResponse</h5>
<div class="paragraph">
<p><code>ServerResponse</code> provides access to the HTTP response and, since it is immutable, you can use
a <code>build</code> method to create it. You can use the builder to set the response status, to add response
headers, or to provide a body. The following example creates a 200 (OK) response with JSON
content:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;Person&gt; person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(person, Person.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val person: Person = ...
ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).bodyValue(person)</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example shows how to build a 201 (CREATED) response with a <code>Location</code> header and no body:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI location = ...
ServerResponse.created(location).build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val location: URI = ...
ServerResponse.created(location).build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Depending on the codec used, it is possible to pass hint parameters to customize how the
body is serialized or deserialized. For example, to specify a <a href="https://www.baeldung.com/jackson-json-view-annotation">Jackson JSON view</a>:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">ServerResponse.ok().hint(Jackson2CodecSupport.JSON_VIEW_HINT, MyJacksonView.class).body(...);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">ServerResponse.ok().hint(Jackson2CodecSupport.JSON_VIEW_HINT, MyJacksonView::class.java).body(...)</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="webflux-fn-handler-classes">Handler Classes</h5>
<div class="paragraph">
<p>We can write a handler function as a lambda, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HandlerFunction&lt;ServerResponse&gt; helloWorld =
  request -&gt; ServerResponse.ok().bodyValue("Hello World");</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val helloWorld = HandlerFunction&lt;ServerResponse&gt; { ServerResponse.ok().bodyValue("Hello World") }</code></pre>
</div>
</div>
<div class="paragraph">
<p>That is convenient, but in an application we need multiple functions, and multiple inline
lambda&#8217;s can get messy.
Therefore, it is useful to group related handler functions together into a handler class, which
has a similar role as  <code>@Controller</code> in an annotation-based application.
For example, the following class exposes a reactive <code>Person</code> repository:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

public class PersonHandler {

    private final PersonRepository repository;

    public PersonHandler(PersonRepository repository) {
        this.repository = repository;
    }

    public Mono&lt;ServerResponse&gt; listPeople(ServerRequest request) { <i class="conum" data-value="1"></i><b>(1)</b>
        Flux&lt;Person&gt; people = repository.allPeople();
        return ok().contentType(APPLICATION_JSON).body(people, Person.class);
    }

    public Mono&lt;ServerResponse&gt; createPerson(ServerRequest request) { <i class="conum" data-value="2"></i><b>(2)</b>
        Mono&lt;Person&gt; person = request.bodyToMono(Person.class);
        return ok().build(repository.savePerson(person));
    }

    public Mono&lt;ServerResponse&gt; getPerson(ServerRequest request) { <i class="conum" data-value="3"></i><b>(3)</b>
        int personId = Integer.valueOf(request.pathVariable("id"));
        return repository.getPerson(personId)
            .flatMap(person -&gt; ok().contentType(APPLICATION_JSON).bodyValue(person))
            .switchIfEmpty(ServerResponse.notFound().build());
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td><code>listPeople</code> is a handler function that returns all <code>Person</code> objects found in the repository as
JSON.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td><code>createPerson</code> is a handler function that stores a new <code>Person</code> contained in the request body.
Note that <code>PersonRepository.savePerson(Person)</code> returns <code>Mono&lt;Void&gt;</code>: an empty <code>Mono</code> that emits
a completion signal when the person has been read from the request and stored. So we use the
<code>build(Publisher&lt;Void&gt;)</code> method to send a response when that completion signal is received (that is,
when the <code>Person</code> has been saved).</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td><code>getPerson</code> is a handler function that returns a single person, identified by the <code>id</code> path
variable. We retrieve that <code>Person</code> from the repository and create a JSON response, if it is
found. If it is not found, we use <code>switchIfEmpty(Mono&lt;T&gt;)</code> to return a 404 Not Found response.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">class PersonHandler(private val repository: PersonRepository) {

    suspend fun listPeople(request: ServerRequest): ServerResponse { <i class="conum" data-value="1"></i><b>(1)</b>
        val people: Flow&lt;Person&gt; = repository.allPeople()
        return ok().contentType(APPLICATION_JSON).bodyAndAwait(people);
    }

    suspend fun createPerson(request: ServerRequest): ServerResponse { <i class="conum" data-value="2"></i><b>(2)</b>
        val person = request.awaitBody&lt;Person&gt;()
        repository.savePerson(person)
        return ok().buildAndAwait()
    }

    suspend fun getPerson(request: ServerRequest): ServerResponse { <i class="conum" data-value="3"></i><b>(3)</b>
        val personId = request.pathVariable("id").toInt()
        return repository.getPerson(personId)?.let { ok().contentType(APPLICATION_JSON).bodyValueAndAwait(it) }
                ?: ServerResponse.notFound().buildAndAwait()

    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td><code>listPeople</code> is a handler function that returns all <code>Person</code> objects found in the repository as
JSON.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td><code>createPerson</code> is a handler function that stores a new <code>Person</code> contained in the request body.
Note that <code>PersonRepository.savePerson(Person)</code> is a suspending function with no return type.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td><code>getPerson</code> is a handler function that returns a single person, identified by the <code>id</code> path
variable. We retrieve that <code>Person</code> from the repository and create a JSON response, if it is
found. If it is not found, we return a 404 Not Found response.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-fn-handler-validation">Validation</h5>
<div class="paragraph">
<p>A functional endpoint can use Spring&#8217;s <a href="core.html#validation">validation facilities</a> to
apply validation to the request body. For example, given a custom Spring
<a href="core.html#validation">Validator</a> implementation for a <code>Person</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">public class PersonHandler {

    private final Validator validator = new PersonValidator(); <i class="conum" data-value="1"></i><b>(1)</b>

    // ...

    public Mono&lt;ServerResponse&gt; createPerson(ServerRequest request) {
        Mono&lt;Person&gt; person = request.bodyToMono(Person.class).doOnNext(this::validate); <i class="conum" data-value="2"></i><b>(2)</b>
        return ok().build(repository.savePerson(person));
    }

    private void validate(Person person) {
        Errors errors = new BeanPropertyBindingResult(person, "person");
        validator.validate(person, errors);
        if (errors.hasErrors()) {
            throw new ServerWebInputException(errors.toString()); <i class="conum" data-value="3"></i><b>(3)</b>
        }
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Create <code>Validator</code> instance.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Apply validation.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Raise exception for a 400 response.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">class PersonHandler(private val repository: PersonRepository) {

    private val validator = PersonValidator() <i class="conum" data-value="1"></i><b>(1)</b>

    // ...

    suspend fun createPerson(request: ServerRequest): ServerResponse {
        val person = request.awaitBody&lt;Person&gt;()
        validate(person) <i class="conum" data-value="2"></i><b>(2)</b>
        repository.savePerson(person)
        return ok().buildAndAwait()
    }

    private fun validate(person: Person) {
        val errors: Errors = BeanPropertyBindingResult(person, "person");
        validator.validate(person, errors);
        if (errors.hasErrors()) {
            throw ServerWebInputException(errors.toString()) <i class="conum" data-value="3"></i><b>(3)</b>
        }
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Create <code>Validator</code> instance.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Apply validation.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Raise exception for a 400 response.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Handlers can also use the standard bean validation API (JSR-303) by creating and injecting
a global <code>Validator</code> instance based on <code>LocalValidatorFactoryBean</code>.
See <a href="core.html#validation-beanvalidation">Spring Validation</a>.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-fn-router-functions">1.5.3. <code>RouterFunction</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#webmvc-fn-router-functions">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Router functions are used to route the requests to the corresponding <code>HandlerFunction</code>.
Typically, you do not write router functions yourself, but rather use a method on the
<code>RouterFunctions</code> utility class to create one.
<code>RouterFunctions.route()</code> (no parameters) provides you with a fluent builder for creating a router
function, whereas <code>RouterFunctions.route(RequestPredicate, HandlerFunction)</code> offers a direct way
to create a router.</p>
</div>
<div class="paragraph">
<p>Generally, it is recommended to use the <code>route()</code> builder, as it provides
convenient short-cuts for typical mapping scenarios without requiring hard-to-discover
static imports.
For instance, the router function builder offers the method <code>GET(String, HandlerFunction)</code> to create a mapping for GET requests; and <code>POST(String, HandlerFunction)</code> for POSTs.</p>
</div>
<div class="paragraph">
<p>Besides HTTP method-based mapping, the route builder offers a way to introduce additional
predicates when mapping to requests.
For each HTTP method there is an overloaded variant that takes a <code>RequestPredicate</code> as a
parameter, though which additional constraints can be expressed.</p>
</div>
<div class="sect4">
<h5 id="webflux-fn-predicates">Predicates</h5>
<div class="paragraph">
<p>You can write your own <code>RequestPredicate</code>, but the <code>RequestPredicates</code> utility class
offers commonly used implementations, based on the request path, HTTP method, content-type,
and so on.
The following example uses a request predicate to create a constraint based on the <code>Accept</code>
header:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RouterFunction&lt;ServerResponse&gt; route = RouterFunctions.route()
    .GET("/hello-world", accept(MediaType.TEXT_PLAIN),
        request -&gt; ServerResponse.ok().bodyValue("Hello World")).build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val route = coRouter {
    GET("/hello-world", accept(TEXT_PLAIN)) {
        ServerResponse.ok().bodyValueAndAwait("Hello World")
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can compose multiple request predicates together by using:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>RequestPredicate.and(RequestPredicate)</code>&#8201;&#8212;&#8201;both must match.</p>
</li>
<li>
<p><code>RequestPredicate.or(RequestPredicate)</code>&#8201;&#8212;&#8201;either can match.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Many of the predicates from <code>RequestPredicates</code> are composed.
For example, <code>RequestPredicates.GET(String)</code> is composed from <code>RequestPredicates.method(HttpMethod)</code>
and <code>RequestPredicates.path(String)</code>.
The example shown above also uses two request predicates, as the builder uses
<code>RequestPredicates.GET</code> internally, and composes that with the <code>accept</code> predicate.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-fn-routes">Routes</h5>
<div class="paragraph">
<p>Router functions are evaluated in order: if the first route does not match, the
second is evaluated, and so on.
Therefore, it makes sense to declare more specific routes before general ones.
This is also important when registering router functions as Spring beans, as will
be described later.
Note that this behavior is different from the annotation-based programming model, where the
"most specific" controller method is picked automatically.</p>
</div>
<div class="paragraph">
<p>When using the router function builder, all defined routes are composed into one
<code>RouterFunction</code> that is returned from <code>build()</code>.
There are also other ways to compose multiple router functions together:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>add(RouterFunction)</code> on the <code>RouterFunctions.route()</code> builder</p>
</li>
<li>
<p><code>RouterFunction.and(RouterFunction)</code></p>
</li>
<li>
<p><code>RouterFunction.andRoute(RequestPredicate, HandlerFunction)</code>&#8201;&#8212;&#8201;shortcut for
<code>RouterFunction.and()</code> with nested <code>RouterFunctions.route()</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The following example shows the composition of four routes:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.web.reactive.function.server.RequestPredicates.*;

PersonRepository repository = ...
PersonHandler handler = new PersonHandler(repository);

RouterFunction&lt;ServerResponse&gt; otherRoute = ...

RouterFunction&lt;ServerResponse&gt; route = route()
    .GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) <i class="conum" data-value="1"></i><b>(1)</b>
    .GET("/person", accept(APPLICATION_JSON), handler::listPeople) <i class="conum" data-value="2"></i><b>(2)</b>
    .POST("/person", handler::createPerson) <i class="conum" data-value="3"></i><b>(3)</b>
    .add(otherRoute) <i class="conum" data-value="4"></i><b>(4)</b>
    .build();</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td><code>GET /person/{id}</code> with an <code>Accept</code> header that matches JSON is routed to
<code>PersonHandler.getPerson</code></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td><code>GET /person</code> with an <code>Accept</code> header that matches JSON is routed to
<code>PersonHandler.listPeople</code></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td><code>POST /person</code> with no additional predicates is mapped to
<code>PersonHandler.createPerson</code>, and</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td><code>otherRoute</code> is a router function that is created elsewhere, and added to the route built.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.http.MediaType.APPLICATION_JSON

val repository: PersonRepository = ...
val handler = PersonHandler(repository);

val otherRoute: RouterFunction&lt;ServerResponse&gt; = coRouter {  }

val route = coRouter {
    GET("/person/{id}", accept(APPLICATION_JSON), handler::getPerson) <i class="conum" data-value="1"></i><b>(1)</b>
    GET("/person", accept(APPLICATION_JSON), handler::listPeople) <i class="conum" data-value="2"></i><b>(2)</b>
    POST("/person", handler::createPerson) <i class="conum" data-value="3"></i><b>(3)</b>
}.and(otherRoute) <i class="conum" data-value="4"></i><b>(4)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td><code>GET /person/{id}</code> with an <code>Accept</code> header that matches JSON is routed to
<code>PersonHandler.getPerson</code></td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td><code>GET /person</code> with an <code>Accept</code> header that matches JSON is routed to
<code>PersonHandler.listPeople</code></td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td><code>POST /person</code> with no additional predicates is mapped to
<code>PersonHandler.createPerson</code>, and</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td><code>otherRoute</code> is a router function that is created elsewhere, and added to the route built.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="_nested_routes">Nested Routes</h5>
<div class="paragraph">
<p>It is common for a group of router functions to have a shared predicate, for instance a
shared path. In the example above, the shared predicate would be a path predicate that
matches <code>/person</code>, used by three of the routes. When using annotations, you would remove
this duplication by using a type-level <code>@RequestMapping</code> annotation that maps to
<code>/person</code>. In WebFlux.fn, path predicates can be shared through the <code>path</code> method on the
router function builder. For instance, the last few lines of the example above can be
improved in the following way by using nested routes:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RouterFunction&lt;ServerResponse&gt; route = route()
    .path("/person", builder -&gt; builder <i class="conum" data-value="1"></i><b>(1)</b>
        .GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
        .GET(accept(APPLICATION_JSON), handler::listPeople)
        .POST("/person", handler::createPerson))
    .build();</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Note that second parameter of <code>path</code> is a consumer that takes the a router builder.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val route = coRouter {
    "/person".nest {
        GET("/{id}", accept(APPLICATION_JSON), handler::getPerson)
        GET(accept(APPLICATION_JSON), handler::listPeople)
        POST("/person", handler::createPerson)
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Though path-based nesting is the most common, you can nest on any kind of predicate by using
the <code>nest</code> method on the builder.
The above still contains some duplication in the form of the shared <code>Accept</code>-header predicate.
We can further improve by using the <code>nest</code> method together with <code>accept</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RouterFunction&lt;ServerResponse&gt; route = route()
    .path("/person", b1 -&gt; b1
        .nest(accept(APPLICATION_JSON), b2 -&gt; b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople))
        .POST("/person", handler::createPerson))
    .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val route = coRouter {
    "/person".nest {
        accept(APPLICATION_JSON).nest {
            GET("/{id}", handler::getPerson)
            GET(handler::listPeople)
            POST("/person", handler::createPerson)
        }
    }
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-fn-running">1.5.4. Running a Server</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#webmvc-fn-running">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>How do you run a router function in an HTTP server? A simple option is to convert a router
function to an <code>HttpHandler</code> by using one of the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>RouterFunctions.toHttpHandler(RouterFunction)</code></p>
</li>
<li>
<p><code>RouterFunctions.toHttpHandler(RouterFunction, HandlerStrategies)</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You can then use the returned <code>HttpHandler</code> with a number of server adapters by following
<a href="web-reactive.html#webflux-httphandler">HttpHandler</a> for server-specific instructions.</p>
</div>
<div class="paragraph">
<p>A more typical option, also used by Spring Boot, is to run with a
<a href="web-reactive.html#webflux-dispatcher-handler"><code>DispatcherHandler</code></a>-based setup through the
<a href="web-reactive.html#webflux-config">web-reactive.html</a>, which uses Spring configuration to declare the
components required to process requests. The WebFlux Java configuration declares the following
infrastructure components to support functional endpoints:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>RouterFunctionMapping</code>: Detects one or more <code>RouterFunction&lt;?&gt;</code> beans in the Spring
configuration, <a href="core.html#beans-factory-ordered">orders them</a>, combines them through
<code>RouterFunction.andOther</code>, and routes requests to the resulting composed <code>RouterFunction</code>.</p>
</li>
<li>
<p><code>HandlerFunctionAdapter</code>: Simple adapter that lets <code>DispatcherHandler</code> invoke
a <code>HandlerFunction</code> that was mapped to a request.</p>
</li>
<li>
<p><code>ServerResponseResultHandler</code>: Handles the result from the invocation of a
<code>HandlerFunction</code> by invoking the <code>writeTo</code> method of the <code>ServerResponse</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The preceding components let functional endpoints fit within the <code>DispatcherHandler</code> request
processing lifecycle and also (potentially) run side by side with annotated controllers, if
any are declared. It is also how functional endpoints are enabled by the Spring Boot WebFlux
starter.</p>
</div>
<div class="paragraph">
<p>The following example shows a WebFlux Java configuration (see
<a href="web-reactive.html#webflux-dispatcher-handler">DispatcherHandler</a> for how to run it):</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Bean
    public RouterFunction&lt;?&gt; routerFunctionA() {
        // ...
    }

    @Bean
    public RouterFunction&lt;?&gt; routerFunctionB() {
        // ...
    }

    // ...

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        // configure message conversion...
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // configure CORS...
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // configure view resolution for HTML rendering...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Bean
    fun routerFunctionA(): RouterFunction&lt;*&gt; {
        // ...
    }

    @Bean
    fun routerFunctionB(): RouterFunction&lt;*&gt; {
        // ...
    }

    // ...

    override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
        // configure message conversion...
    }

    override fun addCorsMappings(registry: CorsRegistry) {
        // configure CORS...
    }

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        // configure view resolution for HTML rendering...
    }
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-fn-handler-filter-function">1.5.5. Filtering Handler Functions</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#webmvc-fn-handler-filter-function">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can filter handler functions by using the <code>before</code>, <code>after</code>, or <code>filter</code> methods on the routing
function builder.
With annotations, you can achieve similar functionality by using <code>@ControllerAdvice</code>, a <code>ServletFilter</code>, or both.
The filter will apply to all routes that are built by the builder.
This means that filters defined in nested routes do not apply to "top-level" routes.
For instance, consider the following example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RouterFunction&lt;ServerResponse&gt; route = route()
    .path("/person", b1 -&gt; b1
        .nest(accept(APPLICATION_JSON), b2 -&gt; b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople)
            .before(request -&gt; ServerRequest.from(request) <i class="conum" data-value="1"></i><b>(1)</b>
                .header("X-RequestHeader", "Value")
                .build()))
        .POST("/person", handler::createPerson))
    .after((request, response) -&gt; logResponse(response)) <i class="conum" data-value="2"></i><b>(2)</b>
    .build();</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The <code>before</code> filter that adds a custom request header is only applied to the two GET routes.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The <code>after</code> filter that logs the response is applied to all routes, including the nested ones.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val route = router {
    "/person".nest {
        GET("/{id}", handler::getPerson)
        GET("", handler::listPeople)
        before { <i class="conum" data-value="1"></i><b>(1)</b>
            ServerRequest.from(it)
                    .header("X-RequestHeader", "Value").build()
        }
        POST("/person", handler::createPerson)
        after { _, response -&gt; <i class="conum" data-value="2"></i><b>(2)</b>
            logResponse(response)
        }
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The <code>before</code> filter that adds a custom request header is only applied to the two GET routes.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>The <code>after</code> filter that logs the response is applied to all routes, including the nested ones.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The <code>filter</code> method on the router builder takes a <code>HandlerFilterFunction</code>: a
function that takes a <code>ServerRequest</code> and <code>HandlerFunction</code> and returns a <code>ServerResponse</code>.
The handler function parameter represents the next element in the chain.
This is typically the handler that is routed to, but it can also be another
filter if multiple are applied.</p>
</div>
<div class="paragraph">
<p>Now we can add a simple security filter to our route, assuming that we have a <code>SecurityManager</code> that
can determine whether a particular path is allowed.
The following example shows how to do so:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">SecurityManager securityManager = ...

RouterFunction&lt;ServerResponse&gt; route = route()
    .path("/person", b1 -&gt; b1
        .nest(accept(APPLICATION_JSON), b2 -&gt; b2
            .GET("/{id}", handler::getPerson)
            .GET(handler::listPeople))
        .POST("/person", handler::createPerson))
    .filter((request, next) -&gt; {
        if (securityManager.allowAccessTo(request.path())) {
            return next.handle(request);
        }
        else {
            return ServerResponse.status(UNAUTHORIZED).build();
        }
    })
    .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val securityManager: SecurityManager = ...

val route = router {
        ("/person" and accept(APPLICATION_JSON)).nest {
            GET("/{id}", handler::getPerson)
            GET("", handler::listPeople)
            POST("/person", handler::createPerson)
            filter { request, next -&gt;
                if (securityManager.allowAccessTo(request.path())) {
                    next(request)
                }
                else {
                    status(UNAUTHORIZED).build();
                }
            }
        }
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>The preceding example demonstrates that invoking the <code>next.handle(ServerRequest)</code> is optional.
We only let the handler function be run when access is allowed.</p>
</div>
<div class="paragraph">
<p>Besides using the <code>filter</code> method on the router function builder, it is possible to apply a
filter to an existing router function via <code>RouterFunction.filter(HandlerFilterFunction)</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
CORS support for functional endpoints is provided through a dedicated
<a href="webflux-cors.html#webflux-cors-webfilter"><code>CorsWebFilter</code></a>.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-uri-building">1.6. URI Links</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-uri-building">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>This section describes various options available in the Spring Framework to prepare URIs.</p>
</div>
<div class="sect3">
<h4 id="web-uricomponents">1.6.1. UriComponents</h4>
<div class="paragraph">
<p><span class="small">Spring MVC and Spring WebFlux</span></p>
</div>
<div class="paragraph">
<p><code>UriComponentsBuilder</code> helps to build URI&#8217;s from URI templates with variables, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">UriComponents uriComponents = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")  <i class="conum" data-value="1"></i><b>(1)</b>
        .queryParam("q", "{q}")  <i class="conum" data-value="2"></i><b>(2)</b>
        .encode() <i class="conum" data-value="3"></i><b>(3)</b>
        .build(); <i class="conum" data-value="4"></i><b>(4)</b>

URI uri = uriComponents.expand("Westin", "123").toUri();  <i class="conum" data-value="5"></i><b>(5)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Static factory method with a URI template.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Add or replace URI components.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Request to have the URI template and URI variables encoded.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Build a <code>UriComponents</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Expand variables and obtain the <code>URI</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uriComponents = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")  <i class="conum" data-value="1"></i><b>(1)</b>
        .queryParam("q", "{q}")  <i class="conum" data-value="2"></i><b>(2)</b>
        .encode() <i class="conum" data-value="3"></i><b>(3)</b>
        .build() <i class="conum" data-value="4"></i><b>(4)</b>

val uri = uriComponents.expand("Westin", "123").toUri()  <i class="conum" data-value="5"></i><b>(5)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Static factory method with a URI template.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Add or replace URI components.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Request to have the URI template and URI variables encoded.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Build a <code>UriComponents</code>.</td>
</tr>
<tr>
<td><i class="conum" data-value="5"></i><b>5</b></td>
<td>Expand variables and obtain the <code>URI</code>.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The preceding example can be consolidated into one chain and shortened with <code>buildAndExpand</code>,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")
        .queryParam("q", "{q}")
        .encode()
        .buildAndExpand("Westin", "123")
        .toUri();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")
        .queryParam("q", "{q}")
        .encode()
        .buildAndExpand("Westin", "123")
        .toUri()</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can shorten it further by going directly to a URI (which implies encoding),
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")
        .queryParam("q", "{q}")
        .build("Westin", "123");</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}")
        .queryParam("q", "{q}")
        .build("Westin", "123")</code></pre>
</div>
</div>
<div class="paragraph">
<p>You shorter it further still with a full URI template, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}?q={q}")
        .build("Westin", "123");</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uri = UriComponentsBuilder
        .fromUriString("https://example.com/hotels/{hotel}?q={q}")
        .build("Westin", "123")</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="web-uribuilder">1.6.2. UriBuilder</h4>
<div class="paragraph">
<p><span class="small">Spring MVC and Spring WebFlux</span></p>
</div>
<div class="paragraph">
<p><a href="#web-uricomponents"><code>UriComponentsBuilder</code></a> implements <code>UriBuilder</code>. You can create a
<code>UriBuilder</code>, in turn, with a <code>UriBuilderFactory</code>. Together, <code>UriBuilderFactory</code> and
<code>UriBuilder</code> provide a pluggable mechanism to build URIs from URI templates, based on
shared configuration, such as a base URL, encoding preferences, and other details.</p>
</div>
<div class="paragraph">
<p>You can configure <code>RestTemplate</code> and <code>WebClient</code> with a <code>UriBuilderFactory</code>
to customize the preparation of URIs. <code>DefaultUriBuilderFactory</code> is a default
implementation of <code>UriBuilderFactory</code> that uses <code>UriComponentsBuilder</code> internally and
exposes shared configuration options.</p>
</div>
<div class="paragraph">
<p>The following example shows how to configure a <code>RestTemplate</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;

String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);

RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode

val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES

val restTemplate = RestTemplate()
restTemplate.uriTemplateHandler = factory</code></pre>
</div>
</div>
<div class="paragraph">
<p>The following example configures a <code>WebClient</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode;

String baseUrl = "https://example.org";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);

WebClient client = WebClient.builder().uriBuilderFactory(factory).build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// import org.springframework.web.util.DefaultUriBuilderFactory.EncodingMode

val baseUrl = "https://example.org"
val factory = DefaultUriBuilderFactory(baseUrl)
factory.encodingMode = EncodingMode.TEMPLATE_AND_VALUES

val client = WebClient.builder().uriBuilderFactory(factory).build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition, you can also use <code>DefaultUriBuilderFactory</code> directly. It is similar to using
<code>UriComponentsBuilder</code> but, instead of static factory methods, it is an actual instance
that holds configuration and preferences, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">String baseUrl = "https://example.com";
DefaultUriBuilderFactory uriBuilderFactory = new DefaultUriBuilderFactory(baseUrl);

URI uri = uriBuilderFactory.uriString("/hotels/{hotel}")
        .queryParam("q", "{q}")
        .build("Westin", "123");</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val baseUrl = "https://example.com"
val uriBuilderFactory = DefaultUriBuilderFactory(baseUrl)

val uri = uriBuilderFactory.uriString("/hotels/{hotel}")
        .queryParam("q", "{q}")
        .build("Westin", "123")</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="web-uri-encoding">1.6.3. URI Encoding</h4>
<div class="paragraph">
<p><span class="small">Spring MVC and Spring WebFlux</span></p>
</div>
<div class="paragraph">
<p><code>UriComponentsBuilder</code> exposes encoding options at two levels:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/util/UriComponentsBuilder.html#encode--">UriComponentsBuilder#encode()</a>:
Pre-encodes the URI template first and then strictly encodes URI variables when expanded.</p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/util/UriComponents.html#encode--">UriComponents#encode()</a>:
Encodes URI components <em>after</em> URI variables are expanded.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Both options replace non-ASCII and illegal characters with escaped octets. However, the first option
also replaces characters with reserved meaning that appear in URI variables.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
Consider ";", which is legal in a path but has reserved meaning. The first option replaces
";" with "%3B" in URI variables but not in the URI template. By contrast, the second option never
replaces ";", since it is a legal character in a path.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For most cases, the first option is likely to give the expected result, because it treats URI
variables as opaque data to be fully encoded, while option 2 is useful only if
URI variables intentionally contain reserved characters.</p>
</div>
<div class="paragraph">
<p>The following example uses the first option:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
        .queryParam("q", "{q}")
        .encode()
        .buildAndExpand("New York", "foo+bar")
        .toUri();

// Result is "/hotel%20list/New%20York?q=foo%2Bbar"</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
        .queryParam("q", "{q}")
        .encode()
        .buildAndExpand("New York", "foo+bar")
        .toUri()

// Result is "/hotel%20list/New%20York?q=foo%2Bbar"</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can shorten the preceding example by going directly to the URI (which implies encoding),
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
        .queryParam("q", "{q}")
        .build("New York", "foo+bar")</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uri = UriComponentsBuilder.fromPath("/hotel list/{city}")
        .queryParam("q", "{q}")
        .build("New York", "foo+bar")</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can shorten it further still with a full URI template, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">URI uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
        .build("New York", "foo+bar")</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val uri = UriComponentsBuilder.fromPath("/hotel list/{city}?q={q}")
        .build("New York", "foo+bar")</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>WebClient</code> and the <code>RestTemplate</code> expand and encode URI templates internally through
the <code>UriBuilderFactory</code> strategy. Both can be configured with a custom strategy.
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">String baseUrl = "https://example.com";
DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl)
factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);

// Customize the RestTemplate..
RestTemplate restTemplate = new RestTemplate();
restTemplate.setUriTemplateHandler(factory);

// Customize the WebClient..
WebClient client = WebClient.builder().uriBuilderFactory(factory).build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val baseUrl = "https://example.com"
val factory = DefaultUriBuilderFactory(baseUrl).apply {
    encodingMode = EncodingMode.TEMPLATE_AND_VALUES
}

// Customize the RestTemplate..
val restTemplate = RestTemplate().apply {
    uriTemplateHandler = factory
}

// Customize the WebClient..
val client = WebClient.builder().uriBuilderFactory(factory).build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>DefaultUriBuilderFactory</code> implementation uses <code>UriComponentsBuilder</code> internally to
expand and encode URI templates. As a factory, it provides a single place to configure
the approach to encoding, based on one of the below encoding modes:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>TEMPLATE_AND_VALUES</code>: Uses <code>UriComponentsBuilder#encode()</code>, corresponding to
the first option in the earlier list, to pre-encode the URI template and strictly encode URI variables when
expanded.</p>
</li>
<li>
<p><code>VALUES_ONLY</code>: Does not encode the URI template and, instead, applies strict encoding
to URI variables through <code>UriUtils#encodeUriUriVariables</code> prior to expanding them into the
template.</p>
</li>
<li>
<p><code>URI_COMPONENT</code>: Uses <code>UriComponents#encode()</code>, corresponding to the second option in the earlier list, to
encode URI component value <em>after</em> URI variables are expanded.</p>
</li>
<li>
<p><code>NONE</code>: No encoding is applied.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>RestTemplate</code> is set to <code>EncodingMode.URI_COMPONENT</code> for historic
reasons and for backwards compatibility. The <code>WebClient</code> relies on the default value
in <code>DefaultUriBuilderFactory</code>, which was changed from <code>EncodingMode.URI_COMPONENT</code> in
5.0.x to <code>EncodingMode.TEMPLATE_AND_VALUES</code> in 5.1.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-cors">1.7. CORS</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-cors">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring WebFlux lets you handle CORS (Cross-Origin Resource Sharing). This section
describes how to do so.</p>
</div>
<div class="sect3">
<h4 id="webflux-cors-intro">1.7.1. Introduction</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-cors-intro">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>For security reasons, browsers prohibit AJAX calls to resources outside the current origin.
For example, you could have your bank account in one tab and evil.com in another. Scripts
from evil.com should not be able to make AJAX requests to your bank API with your
credentials&#8201;&#8212;&#8201;for example, withdrawing money from your account!</p>
</div>
<div class="paragraph">
<p>Cross-Origin Resource Sharing (CORS) is a <a href="https://www.w3.org/TR/cors/">W3C specification</a>
implemented by <a href="https://caniuse.com/#feat=cors">most browsers</a> that lets you specify
what kind of cross-domain requests are authorized, rather than using less secure and less
powerful workarounds based on IFRAME or JSONP.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-cors-processing">1.7.2. Processing</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-cors-processing">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The CORS specification distinguishes between preflight, simple, and actual requests.
To learn how CORS works, you can read
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">this article</a>, among
many others, or see the specification for more details.</p>
</div>
<div class="paragraph">
<p>Spring WebFlux <code>HandlerMapping</code> implementations provide built-in support for CORS. After successfully
mapping a request to a handler, a <code>HandlerMapping</code> checks the CORS configuration for the
given request and handler and takes further actions. Preflight requests are handled
directly, while simple and actual CORS requests are intercepted, validated, and have the
required CORS response headers set.</p>
</div>
<div class="paragraph">
<p>In order to enable cross-origin requests (that is, the <code>Origin</code> header is present and
differs from the host of the request), you need to have some explicitly declared CORS
configuration. If no matching CORS configuration is found, preflight requests are
rejected. No CORS headers are added to the responses of simple and actual CORS requests
and, consequently, browsers reject them.</p>
</div>
<div class="paragraph">
<p>Each <code>HandlerMapping</code> can be
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/handler/AbstractHandlerMapping.html#setCorsConfigurations-java.util.Map-">configured</a>
individually with URL pattern-based <code>CorsConfiguration</code> mappings. In most cases, applications
use the WebFlux Java configuration to declare such mappings, which results in a single,
global map passed to all <code>HandlerMapping</code> implementations.</p>
</div>
<div class="paragraph">
<p>You can combine global CORS configuration at the <code>HandlerMapping</code> level with more
fine-grained, handler-level CORS configuration. For example, annotated controllers can use
class- or method-level <code>@CrossOrigin</code> annotations (other handlers can implement
<code>CorsConfigurationSource</code>).</p>
</div>
<div class="paragraph">
<p>The rules for combining global and local configuration are generally additive&#8201;&#8212;&#8201;for example,
all global and all local origins. For those attributes where only a single value can be
accepted, such as <code>allowCredentials</code> and <code>maxAge</code>, the local overrides the global value. See
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/cors/CorsConfiguration.html#combine-org.springframework.web.cors.CorsConfiguration-"><code>CorsConfiguration#combine(CorsConfiguration)</code></a>
for more details.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>To learn more from the source or to make advanced customizations, see:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>CorsConfiguration</code></p>
</li>
<li>
<p><code>CorsProcessor</code> and <code>DefaultCorsProcessor</code></p>
</li>
<li>
<p><code>AbstractHandlerMapping</code></p>
</li>
</ul>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-cors-controller">1.7.3. <code>@CrossOrigin</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-cors-controller">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/bind/annotation/CrossOrigin.html"><code>@CrossOrigin</code></a>
annotation enables cross-origin requests on annotated controller methods, as the
following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin
    @GetMapping("/{id}")
    public Mono&lt;Account&gt; retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public Mono&lt;Void&gt; remove(@PathVariable Long id) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@RestController
@RequestMapping("/account")
class AccountController {

    @CrossOrigin
    @GetMapping("/{id}")
    suspend fun retrieve(@PathVariable id: Long): Account {
        // ...
    }

    @DeleteMapping("/{id}")
    suspend fun remove(@PathVariable id: Long) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>By default, <code>@CrossOrigin</code> allows:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>All origins.</p>
</li>
<li>
<p>All headers.</p>
</li>
<li>
<p>All HTTP methods to which the controller method is mapped.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>allowCredentials</code> is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information (such as cookies and CSRF tokens) and
should be used only where appropriate. When it is enabled either <code>allowOrigins</code> must be
set to one or more specific domain (but not the special value <code>"*"</code>) or alternatively
the <code>allowOriginPatterns</code> property may be used to match to a dynamic set of origins.</p>
</div>
<div class="paragraph">
<p><code>maxAge</code> is set to 30 minutes.</p>
</div>
<div class="paragraph">
<p><code>@CrossOrigin</code> is supported at the class level, too, and inherited by all methods.
The following example specifies a certain domain and sets <code>maxAge</code> to an hour:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @GetMapping("/{id}")
    public Mono&lt;Account&gt; retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public Mono&lt;Void&gt; remove(@PathVariable Long id) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@CrossOrigin("https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
class AccountController {

    @GetMapping("/{id}")
    suspend fun retrieve(@PathVariable id: Long): Account {
        // ...
    }

    @DeleteMapping("/{id}")
    suspend fun remove(@PathVariable id: Long) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can use <code>@CrossOrigin</code> at both the class and the method level,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@CrossOrigin(maxAge = 3600) <i class="conum" data-value="1"></i><b>(1)</b>
@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin("https://domain2.com") <i class="conum" data-value="2"></i><b>(2)</b>
    @GetMapping("/{id}")
    public Mono&lt;Account&gt; retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public Mono&lt;Void&gt; remove(@PathVariable Long id) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@CrossOrigin</code> at the class level.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using <code>@CrossOrigin</code> at the method level.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@CrossOrigin(maxAge = 3600) <i class="conum" data-value="1"></i><b>(1)</b>
@RestController
@RequestMapping("/account")
class AccountController {

    @CrossOrigin("https://domain2.com") <i class="conum" data-value="2"></i><b>(2)</b>
    @GetMapping("/{id}")
    suspend fun retrieve(@PathVariable id: Long): Account {
        // ...
    }

    @DeleteMapping("/{id}")
    suspend fun remove(@PathVariable id: Long) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Using <code>@CrossOrigin</code> at the class level.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using <code>@CrossOrigin</code> at the method level.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-cors-global">1.7.4. Global Configuration</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-cors-global">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>In addition to fine-grained, controller method-level configuration, you probably want to
define some global CORS configuration, too. You can set URL-based <code>CorsConfiguration</code>
mappings individually on any <code>HandlerMapping</code>. Most applications, however, use the
WebFlux Java configuration to do that.</p>
</div>
<div class="paragraph">
<p>By default global configuration enables the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>All origins.</p>
</li>
<li>
<p>All headers.</p>
</li>
<li>
<p><code>GET</code>, <code>HEAD</code>, and <code>POST</code> methods.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>allowedCredentials</code> is not enabled by default, since that establishes a trust level
that exposes sensitive user-specific information( such as cookies and CSRF tokens) and
should be used only where appropriate. When it is enabled either <code>allowOrigins</code> must be
set to one or more specific domain (but not the special value <code>"*"</code>) or alternatively
the <code>allowOriginPatterns</code> property may be used to match to a dynamic set of origins.</p>
</div>
<div class="paragraph">
<p><code>maxAge</code> is set to 30 minutes.</p>
</div>
<div class="paragraph">
<p>To enable CORS in the WebFlux Java configuration, you can use the <code>CorsRegistry</code> callback,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
            .allowedOrigins("https://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(true).maxAge(3600);

        // Add more mappings...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addCorsMappings(registry: CorsRegistry) {

        registry.addMapping("/api/**")
                .allowedOrigins("https://domain2.com")
                .allowedMethods("PUT", "DELETE")
                .allowedHeaders("header1", "header2", "header3")
                .exposedHeaders("header1", "header2")
                .allowCredentials(true).maxAge(3600)

        // Add more mappings...
    }
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-cors-webfilter">1.7.5. CORS <code>WebFilter</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-cors-filter">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can apply CORS support through the built-in
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/cors/reactive/CorsWebFilter.html"><code>CorsWebFilter</code></a>, which is a
good fit with <a href="#webflux-fn">functional endpoints</a>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If you try to use the <code>CorsFilter</code> with Spring Security, keep in mind that Spring
Security has
<a href="https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#cors">built-in support</a>
for CORS.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To configure the filter, you can declare a <code>CorsWebFilter</code> bean and pass a
<code>CorsConfigurationSource</code> to its constructor, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Bean
CorsWebFilter corsFilter() {

    CorsConfiguration config = new CorsConfiguration();

    // Possibly...
    // config.applyPermitDefaultValues()

    config.setAllowCredentials(true);
    config.addAllowedOrigin("https://domain1.com");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);

    return new CorsWebFilter(source);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Bean
fun corsFilter(): CorsWebFilter {

    val config = CorsConfiguration()

    // Possibly...
    // config.applyPermitDefaultValues()

    config.allowCredentials = true
    config.addAllowedOrigin("https://domain1.com")
    config.addAllowedHeader("*")
    config.addAllowedMethod("*")

    val source = UrlBasedCorsConfigurationSource().apply {
        registerCorsConfiguration("/**", config)
    }
    return CorsWebFilter(source)
}</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-web-security">1.8. Web Security</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-web-security">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <a href="https://projects.spring.io/spring-security/">Spring Security</a> project provides support
for protecting web applications from malicious exploits. See the Spring Security
reference documentation, including:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#jc-webflux">WebFlux Security</a></p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#test-webflux">WebFlux Testing Support</a></p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#csrf">CSRF Protection</a></p>
</li>
<li>
<p><a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#headers">Security Response Headers</a></p>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="webflux-view">1.9. View Technologies</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The use of view technologies in Spring WebFlux is pluggable. Whether you decide to
use Thymeleaf, FreeMarker, or some other view technology is primarily a matter of a
configuration change. This chapter covers the view technologies integrated with Spring
WebFlux. We assume you are already familiar with <a href="#webflux-viewresolution">View Resolution</a>.</p>
</div>
<div class="sect3">
<h4 id="webflux-view-thymeleaf">1.9.1. Thymeleaf</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-thymeleaf">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Thymeleaf is a modern server-side Java template engine that emphasizes natural HTML
templates that can be previewed in a browser by double-clicking, which is very
helpful for independent work on UI templates (for example, by a designer) without the need for a
running server. Thymeleaf offers an extensive set of features, and it is actively developed
and maintained. For a more complete introduction, see the
<a href="https://www.thymeleaf.org/">Thymeleaf</a> project home page.</p>
</div>
<div class="paragraph">
<p>The Thymeleaf integration with Spring WebFlux is managed by the Thymeleaf project. The
configuration involves a few bean declarations, such as
<code>SpringResourceTemplateResolver</code>, <code>SpringWebFluxTemplateEngine</code>, and
<code>ThymeleafReactiveViewResolver</code>. For more details, see
<a href="https://www.thymeleaf.org/documentation.html">Thymeleaf+Spring</a> and the WebFlux integration
<a href="http://forum.thymeleaf.org/Thymeleaf-3-0-8-JUST-PUBLISHED-td4030687.html">announcement</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-view-freemarker">1.9.2. FreeMarker</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-freemarker">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><a href="https://freemarker.apache.org/">Apache FreeMarker</a> is a template engine for generating any
kind of text output from HTML to email and others. The Spring Framework has built-in
integration for using Spring WebFlux with FreeMarker templates.</p>
</div>
<div class="sect4">
<h5 id="webflux-view-freemarker-contextconfig">View Configuration</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-freemarker-contextconfig">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The following example shows how to configure FreeMarker as a view technology:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();
    }

    // Configure FreeMarker...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates/freemarker");
        return configurer;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()
    }

    // Configure FreeMarker...

    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("classpath:/templates/freemarker")
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Your templates need to be stored in the directory specified by the <code>FreeMarkerConfigurer</code>,
shown in the preceding example. Given the preceding configuration, if your controller
returns the view name, <code>welcome</code>, the resolver looks for the
<code>classpath:/templates/freemarker/welcome.ftl</code> template.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-views-freemarker">FreeMarker Configuration</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-views-freemarker">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can pass FreeMarker 'Settings' and 'SharedVariables' directly to the FreeMarker
<code>Configuration</code> object (which is managed by Spring) by setting the appropriate bean
properties on the <code>FreeMarkerConfigurer</code> bean. The <code>freemarkerSettings</code> property requires
a <code>java.util.Properties</code> object, and the <code>freemarkerVariables</code> property requires a
<code>java.util.Map</code>. The following example shows how to use a <code>FreeMarkerConfigurer</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    // ...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        Map&lt;String, Object&gt; variables = new HashMap&lt;&gt;();
        variables.put("xml_escape", new XmlEscape());

        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates");
        configurer.setFreemarkerVariables(variables);
        return configurer;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    // ...

    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("classpath:/templates")
        setFreemarkerVariables(mapOf("xml_escape" to XmlEscape()))
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>See the FreeMarker documentation for details of settings and variables as they apply to
the <code>Configuration</code> object.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-view-freemarker-forms">Form Handling</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-freemarker-forms">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Spring provides a tag library for use in JSPs that contains, among others, a
<code>&lt;spring:bind/&gt;</code> element. This element primarily lets forms display values from
form-backing objects and show the results of failed validations from a <code>Validator</code> in the
web or business tier. Spring also has support for the same functionality in FreeMarker,
with additional convenience macros for generating form input elements themselves.</p>
</div>
<div class="sect5">
<h6 id="webflux-view-bind-macros">The Bind Macros</h6>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-bind-macros">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>A standard set of macros are maintained within the <code>spring-webflux.jar</code> file for
FreeMarker, so they are always available to a suitably configured application.</p>
</div>
<div class="paragraph">
<p>Some of the macros defined in the Spring templating libraries are considered internal
(private), but no such scoping exists in the macro definitions, making all macros visible
to calling code and user templates. The following sections concentrate only on the macros
you need to directly call from within your templates. If you wish to view the macro code
directly, the file is called <code>spring.ftl</code> and is in the
<code>org.springframework.web.reactive.result.view.freemarker</code> package.</p>
</div>
<div class="paragraph">
<p>For additional details on binding support, see <a href="web.html#mvc-view-simple-binding">Simple
Binding</a> for Spring MVC.</p>
</div>
</div>
<div class="sect5">
<h6 id="webflux-views-form-macros">Form Macros</h6>
<div class="paragraph">
<p>For details on Spring&#8217;s form macro support for FreeMarker templates, consult the following
sections of the Spring MVC documentation.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="web.html#mvc-views-form-macros">Input Macros</a></p>
</li>
<li>
<p><a href="web.html#mvc-views-form-macros-input">Input Fields</a></p>
</li>
<li>
<p><a href="web.html#mvc-views-form-macros-select">Selection Fields</a></p>
</li>
<li>
<p><a href="web.html#mvc-views-form-macros-html-escaping">HTML Escaping</a></p>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-view-script">1.9.3. Script Views</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-script">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The Spring Framework has a built-in integration for using Spring WebFlux with any
templating library that can run on top of the
<a href="https://www.jcp.org/en/jsr/detail?id=223">JSR-223</a> Java scripting engine.
The following table shows the templating libraries that we have tested on different script engines:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Scripting Library</th>
<th class="tableblock halign-left valign-top">Scripting Engine</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://handlebarsjs.com/">Handlebars</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://openjdk.java.net/projects/nashorn/">Nashorn</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://mustache.github.io/">Mustache</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://openjdk.java.net/projects/nashorn/">Nashorn</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://facebook.github.io/react/">React</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://openjdk.java.net/projects/nashorn/">Nashorn</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://www.embeddedjs.com/">EJS</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://openjdk.java.net/projects/nashorn/">Nashorn</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://www.stuartellis.name/articles/erb/">ERB</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://www.jruby.org">JRuby</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://docs.python.org/2/library/string.html#template-strings">String templates</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://www.jython.org/">Jython</a></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://github.com/sdeleuze/kotlin-script-templating">Kotlin Script templating</a></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><a href="https://kotlinlang.org/">Kotlin</a></p></td>
</tr>
</tbody>
</table>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
The basic rule for integrating any other script engine is that it must implement the
<code>ScriptEngine</code> and <code>Invocable</code> interfaces.
</td>
</tr>
</table>
</div>
<div class="sect4">
<h5 id="webflux-view-script-dependencies">Requirements</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-script-dependencies">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You need to have the script engine on your classpath, the details of which vary by script engine:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>The <a href="https://openjdk.java.net/projects/nashorn/">Nashorn</a> JavaScript engine is provided with
Java 8+. Using the latest update release available is highly recommended.</p>
</li>
<li>
<p><a href="https://www.jruby.org">JRuby</a> should be added as a dependency for Ruby support.</p>
</li>
<li>
<p><a href="https://www.jython.org">Jython</a> should be added as a dependency for Python support.</p>
</li>
<li>
<p><code>org.jetbrains.kotlin:kotlin-script-util</code> dependency and a <code>META-INF/services/javax.script.ScriptEngineFactory</code>
file containing a <code>org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngineFactory</code>
line should be added for Kotlin script support. See
<a href="https://github.com/sdeleuze/kotlin-script-templating">this example</a> for more detail.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You need to have the script templating library. One way to do that for Javascript is
through <a href="https://www.webjars.org/">WebJars</a>.</p>
</div>
</div>
<div class="sect4">
<h5 id="webflux-view-script-integrate">Script Templates</h5>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-script-integrate">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can declare a <code>ScriptTemplateConfigurer</code> bean to specify the script engine to use,
the script files to load, what function to call to render templates, and so on.
The following example uses Mustache templates and the Nashorn JavaScript engine:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.scriptTemplate();
    }

    @Bean
    public ScriptTemplateConfigurer configurer() {
        ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
        configurer.setEngineName("nashorn");
        configurer.setScripts("mustache.js");
        configurer.setRenderObject("Mustache");
        configurer.setRenderFunction("render");
        return configurer;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.scriptTemplate()
    }

    @Bean
    fun configurer() = ScriptTemplateConfigurer().apply {
        engineName = "nashorn"
        setScripts("mustache.js")
        renderObject = "Mustache"
        renderFunction = "render"
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>render</code> function is called with the following parameters:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>String template</code>: The template content</p>
</li>
<li>
<p><code>Map model</code>: The view model</p>
</li>
<li>
<p><code>RenderingContext renderingContext</code>: The
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/servlet/view/script/RenderingContext.html"><code>RenderingContext</code></a>
that gives access to the application context, the locale, the template loader, and the
URL (since 5.0)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p><code>Mustache.render()</code> is natively compatible with this signature, so you can call it directly.</p>
</div>
<div class="paragraph">
<p>If your templating technology requires some customization, you can provide a script that
implements a custom render function. For example, <a href="https://handlebarsjs.com">Handlerbars</a>
needs to compile templates before using them and requires a
<a href="https://en.wikipedia.org/wiki/Polyfill">polyfill</a> in order to emulate some
browser facilities not available in the server-side script engine.
The following example shows how to set a custom render function:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.scriptTemplate();
    }

    @Bean
    public ScriptTemplateConfigurer configurer() {
        ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
        configurer.setEngineName("nashorn");
        configurer.setScripts("polyfill.js", "handlebars.js", "render.js");
        configurer.setRenderFunction("render");
        configurer.setSharedEngine(false);
        return configurer;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.scriptTemplate()
    }

    @Bean
    fun configurer() = ScriptTemplateConfigurer().apply {
        engineName = "nashorn"
        setScripts("polyfill.js", "handlebars.js", "render.js")
        renderFunction = "render"
        isSharedEngine = false
    }
}</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
Setting the <code>sharedEngine</code> property to <code>false</code> is required when using non-thread-safe
script engines with templating libraries not designed for concurrency, such as Handlebars or
React running on Nashorn. In that case, Java SE 8 update 60 is required, due to
<a href="https://bugs.openjdk.java.net/browse/JDK-8076099">this bug</a>, but it is generally
recommended to use a recent Java SE patch release in any case.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><code>polyfill.js</code> defines only the <code>window</code> object needed by Handlebars to run properly,
as the following snippet shows:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="javascript">var window = {};</code></pre>
</div>
</div>
<div class="paragraph">
<p>This basic <code>render.js</code> implementation compiles the template before using it. A production
ready implementation should also store and reused cached templates or pre-compiled templates.
This can be done on the script side, as well as any customization you need (managing
template engine configuration for example).
The following example shows how compile a template:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="javascript">function render(template, model) {
    var compiledTemplate = Handlebars.compile(template);
    return compiledTemplate(model);
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Check out the Spring Framework unit tests,
<a href="https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/java/org/springframework/web/reactive/result/view/script">Java</a>, and
<a href="https://github.com/spring-projects/spring-framework/tree/master/spring-webflux/src/test/resources/org/springframework/web/reactive/result/view/script">resources</a>,
for more configuration examples.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-view-httpmessagewriter">1.9.4. JSON and XML</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-view-jackson">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>For <a href="#webflux-multiple-representations">Content Negotiation</a> purposes, it is useful to be able to alternate
between rendering a model with an HTML template or as other formats (such as JSON or XML),
depending on the content type requested by the client. To support doing so, Spring WebFlux
provides the <code>HttpMessageWriterView</code>, which you can use to plug in any of the available
<a href="#webflux-codecs">Codecs</a> from <code>spring-web</code>, such as <code>Jackson2JsonEncoder</code>, <code>Jackson2SmileEncoder</code>,
or <code>Jaxb2XmlEncoder</code>.</p>
</div>
<div class="paragraph">
<p>Unlike other view technologies, <code>HttpMessageWriterView</code> does not require a <code>ViewResolver</code>
but is instead <a href="#webflux-config-view-resolvers">configured</a> as a default view. You can
configure one or more such default views, wrapping different <code>HttpMessageWriter</code> instances
or <code>Encoder</code> instances. The one that matches the requested content type is used at runtime.</p>
</div>
<div class="paragraph">
<p>In most cases, a model contains multiple attributes. To determine which one to serialize,
you can configure <code>HttpMessageWriterView</code> with the name of the model attribute to use for
rendering. If the model contains only one attribute, that one is used.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-caching">1.10. HTTP Caching</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-caching">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>HTTP caching can significantly improve the performance of a web application. HTTP caching
revolves around the <code>Cache-Control</code> response header and subsequent conditional request
headers, such as <code>Last-Modified</code> and <code>ETag</code>. <code>Cache-Control</code> advises private (for example, browser)
and public (for example, proxy) caches how to cache and re-use responses. An <code>ETag</code> header is used
to make a conditional request that may result in a 304 (NOT_MODIFIED) without a body,
if the content has not changed. <code>ETag</code> can be seen as a more sophisticated successor to
the <code>Last-Modified</code> header.</p>
</div>
<div class="paragraph">
<p>This section describes the HTTP caching related options available in Spring WebFlux.</p>
</div>
<div class="sect3">
<h4 id="webflux-caching-cachecontrol">1.10.1. <code>CacheControl</code></h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-caching-cachecontrol">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/http/CacheControl.html"><code>CacheControl</code></a> provides support for
configuring settings related to the <code>Cache-Control</code> header and is accepted as an argument
in a number of places:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#webflux-caching-etag-lastmodified">Controllers</a></p>
</li>
<li>
<p><a href="#webflux-caching-static-resources">Static Resources</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>While <a href="https://tools.ietf.org/html/rfc7234#section-5.2.2">RFC 7234</a> describes all possible
directives for the <code>Cache-Control</code> response header, the <code>CacheControl</code> type takes a
use case-oriented approach that focuses on the common scenarios, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">// Cache for an hour - "Cache-Control: max-age=3600"
CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);

// Prevent caching - "Cache-Control: no-store"
CacheControl ccNoStore = CacheControl.noStore();

// Cache for ten days in public and private caches,
// public caches should not transform the response
// "Cache-Control: max-age=864000, public, no-transform"
CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">// Cache for an hour - "Cache-Control: max-age=3600"
val ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS)

// Prevent caching - "Cache-Control: no-store"
val ccNoStore = CacheControl.noStore()

// Cache for ten days in public and private caches,
// public caches should not transform the response
// "Cache-Control: max-age=864000, public, no-transform"
val ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic()</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-caching-etag-lastmodified">1.10.2. Controllers</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-caching-etag-lastmodified">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>Controllers can add explicit support for HTTP caching. We recommend doing so, since the
<code>lastModified</code> or <code>ETag</code> value for a resource needs to be calculated before it can be compared
against conditional request headers. A controller can add an <code>ETag</code> and <code>Cache-Control</code>
settings to a <code>ResponseEntity</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@GetMapping("/book/{id}")
public ResponseEntity&lt;Book&gt; showBook(@PathVariable Long id) {

    Book book = findBook(id);
    String version = book.getVersion();

    return ResponseEntity
            .ok()
            .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
            .eTag(version) // lastModified is also available
            .body(book);
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@GetMapping("/book/{id}")
fun showBook(@PathVariable id: Long): ResponseEntity&lt;Book&gt; {

    val book = findBook(id)
    val version = book.getVersion()

    return ResponseEntity
            .ok()
            .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
            .eTag(version) // lastModified is also available
            .body(book)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The preceding example sends a 304 (NOT_MODIFIED) response with an empty body if the comparison
to the conditional request headers indicates the content has not changed. Otherwise, the
<code>ETag</code> and <code>Cache-Control</code> headers are added to the response.</p>
</div>
<div class="paragraph">
<p>You can also make the check against conditional request headers in the controller,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@RequestMapping
public String myHandleMethod(ServerWebExchange exchange, Model model) {

    long eTag = ... <i class="conum" data-value="1"></i><b>(1)</b>

    if (exchange.checkNotModified(eTag)) {
        return null; <i class="conum" data-value="2"></i><b>(2)</b>
    }

    model.addAttribute(...); <i class="conum" data-value="3"></i><b>(3)</b>
    return "myViewName";
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Application-specific calculation.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Response has been set to 304 (NOT_MODIFIED). No further processing.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Continue with request processing.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@RequestMapping
fun myHandleMethod(exchange: ServerWebExchange, model: Model): String? {

    val eTag: Long = ... <i class="conum" data-value="1"></i><b>(1)</b>

    if (exchange.checkNotModified(eTag)) {
        return null<i class="conum" data-value="2"></i><b>(2)</b>
    }

    model.addAttribute(...) <i class="conum" data-value="3"></i><b>(3)</b>
    return "myViewName"
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Application-specific calculation.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Response has been set to 304 (NOT_MODIFIED). No further processing.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Continue with request processing.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>There are three variants for checking conditional requests against <code>eTag</code> values, <code>lastModified</code>
values, or both. For conditional <code>GET</code> and <code>HEAD</code> requests, you can set the response to
304 (NOT_MODIFIED). For conditional <code>POST</code>, <code>PUT</code>, and <code>DELETE</code>, you can instead set the response
to 412 (PRECONDITION_FAILED) to prevent concurrent modification.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-caching-static-resources">1.10.3. Static Resources</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-caching-static-resources">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You should serve static resources with a <code>Cache-Control</code> and conditional response headers
for optimal performance. See the section on configuring <a href="#webflux-config-static-resources">Static Resources</a>.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-config">1.11. WebFlux Config</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The WebFlux Java configuration declares the components that are required to process
requests with annotated controllers or functional endpoints, and it offers an API to
customize the configuration. That means you do not need to understand the underlying
beans created by the Java configuration. However, if you want to understand them,
you can see them in <code>WebFluxConfigurationSupport</code> or read more about what they are
in <a href="#webflux-special-bean-types">Special Bean Types</a>.</p>
</div>
<div class="paragraph">
<p>For more advanced customizations, not available in the configuration API, you can
gain full control over the configuration through the
<a href="#webflux-config-advanced-java">Advanced Configuration Mode</a>.</p>
</div>
<div class="sect3">
<h4 id="webflux-config-enable">1.11.1. Enabling WebFlux Config</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-enable">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can use the <code>@EnableWebFlux</code> annotation in your Java config, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig {
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig</code></pre>
</div>
</div>
<div class="paragraph">
<p>The preceding example registers a number of Spring WebFlux
<a href="#webflux-special-bean-types">infrastructure beans</a> and adapts to dependencies
available on the classpath&#8201;&#8212;&#8201;for JSON, XML, and others.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-customize">1.11.2. WebFlux config API</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-customize">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>In your Java configuration, you can implement the <code>WebFluxConfigurer</code> interface,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    // Implement configuration methods...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    // Implement configuration methods...
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-conversion">1.11.3. Conversion, formatting</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-conversion">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>By default, formatters for various number and date types are installed, along with support
for customization via <code>@NumberFormat</code> and <code>@DateTimeFormat</code> on fields.</p>
</div>
<div class="paragraph">
<p>To register custom formatters and converters in Java config, use the following:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ...
    }

}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addFormatters(registry: FormatterRegistry) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>By default Spring WebFlux considers the request Locale when parsing and formatting date
values. This works for forms where dates are represented as Strings with "input" form
fields. For "date" and "time" form fields, however, browsers use a fixed format defined
in the HTML spec. For such cases date and time formatting can be customized as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addFormatters(registry: FormatterRegistry) {
        val registrar = DateTimeFormatterRegistrar()
        registrar.setUseIsoFormat(true)
        registrar.registerFormatters(registry)
    }
}</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
See <a href="core.html#format-FormatterRegistrar-SPI"><code>FormatterRegistrar</code> SPI</a>
and the <code>FormattingConversionServiceFactoryBean</code> for more information on when to
use <code>FormatterRegistrar</code> implementations.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-validation">1.11.4. Validation</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-validation">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>By default, if <a href="core.html#validation-beanvalidation-overview">Bean Validation</a> is present
on the classpath (for example, the Hibernate Validator), the <code>LocalValidatorFactoryBean</code>
is registered as a global <a href="core.html#validator">validator</a> for use with <code>@Valid</code> and
<code>@Validated</code> on <code>@Controller</code> method arguments.</p>
</div>
<div class="paragraph">
<p>In your Java configuration, you can customize the global <code>Validator</code> instance,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public Validator getValidator(); {
        // ...
    }

}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun getValidator(): Validator {
        // ...
    }

}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that you can also register <code>Validator</code> implementations locally,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
public class MyController {

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new FooValidator());
    }

}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
class MyController {

    @InitBinder
    protected fun initBinder(binder: WebDataBinder) {
        binder.addValidators(FooValidator())
    }
}</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
If you need to have a <code>LocalValidatorFactoryBean</code> injected somewhere, create a bean and
mark it with <code>@Primary</code> in order to avoid conflict with the one declared in the MVC config.
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-content-negotiation">1.11.5. Content Type Resolvers</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-content-negotiation">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can configure how Spring WebFlux determines the requested media types for
<code>@Controller</code> instances from the request. By default, only the <code>Accept</code> header is checked,
but you can also enable a query parameter-based strategy.</p>
</div>
<div class="paragraph">
<p>The following example shows how to customize the requested content type resolution:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureContentTypeResolver(builder: RequestedContentTypeResolverBuilder) {
        // ...
    }
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-message-codecs">1.11.6. HTTP message codecs</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-message-converters">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The following example shows how to customize how the request and response body are read and written:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.defaultCodecs().maxInMemorySize(512 * 1024);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>ServerCodecConfigurer</code> provides a set of default readers and writers. You can use it to add
more readers and writers, customize the default ones, or replace the default ones completely.</p>
</div>
<div class="paragraph">
<p>For Jackson JSON and XML, consider using
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.html"><code>Jackson2ObjectMapperBuilder</code></a>,
which customizes Jackson&#8217;s default properties with the following ones:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/DeserializationFeature.html#FAIL_ON_UNKNOWN_PROPERTIES"><code>DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES</code></a> is disabled.</p>
</li>
<li>
<p><a href="https://fasterxml.github.io/jackson-databind/javadoc/2.6/com/fasterxml/jackson/databind/MapperFeature.html#DEFAULT_VIEW_INCLUSION"><code>MapperFeature.DEFAULT_VIEW_INCLUSION</code></a> is disabled.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>It also automatically registers the following well-known modules if they are detected on the classpath:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/FasterXML/jackson-datatype-joda"><code>jackson-datatype-joda</code></a>: Support for Joda-Time types.</p>
</li>
<li>
<p><a href="https://github.com/FasterXML/jackson-datatype-jsr310"><code>jackson-datatype-jsr310</code></a>: Support for Java 8 Date and Time API types.</p>
</li>
<li>
<p><a href="https://github.com/FasterXML/jackson-datatype-jdk8"><code>jackson-datatype-jdk8</code></a>: Support for other Java 8 types, such as <code>Optional</code>.</p>
</li>
<li>
<p><a href="https://github.com/FasterXML/jackson-module-kotlin"><code>jackson-module-kotlin</code></a>: Support for Kotlin classes and data classes.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-view-resolvers">1.11.7. View Resolvers</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-view-resolvers">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>The following example shows how to configure view resolution:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>ViewResolverRegistry</code> has shortcuts for view technologies with which the Spring Framework
integrates. The following example uses FreeMarker (which also requires configuring the
underlying FreeMarker view technology):</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();
    }

    // Configure Freemarker...

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("classpath:/templates");
        return configurer;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()
    }

    // Configure Freemarker...

    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("classpath:/templates")
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can also plug in any <code>ViewResolver</code> implementation, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        ViewResolver resolver = ... ;
        registry.viewResolver(resolver);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        val resolver: ViewResolver = ...
        registry.viewResolver(resolver
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>To support <a href="#webflux-multiple-representations">Content Negotiation</a> and rendering other formats
through view resolution (besides HTML), you can configure one or more default views based
on the <code>HttpMessageWriterView</code> implementation, which accepts any of the available
<a href="#webflux-codecs">Codecs</a> from <code>spring-web</code>. The following example shows how to do so:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {


    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.freeMarker();

        Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
        registry.defaultViews(new HttpMessageWriterView(encoder));
    }

    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {


    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.freeMarker()

        val encoder = Jackson2JsonEncoder()
        registry.defaultViews(HttpMessageWriterView(encoder))
    }

    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>See <a href="#webflux-view">View Technologies</a> for more on the view technologies that are integrated with Spring WebFlux.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-static-resources">1.11.8. Static Resources</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-static-resources">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>This option provides a convenient way to serve static resources from a list of
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/io/Resource.html"><code>Resource</code></a>-based locations.</p>
</div>
<div class="paragraph">
<p>In the next example, given a request that starts with <code>/resources</code>, the relative path is
used to find and serve static resources relative to <code>/static</code> on the classpath. Resources
are served with a one-year future expiration to ensure maximum use of the browser cache
and a reduction in HTTP requests made by the browser. The <code>Last-Modified</code> header is also
evaluated and, if present, a <code>304</code> status code is returned. The following list shows
the example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
            .addResourceLocations("/public", "classpath:/static/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }

}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The resource handler also supports a chain of
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/resource/ResourceResolver.html"><code>ResourceResolver</code></a> implementations and
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/resource/ResourceTransformer.html"><code>ResourceTransformer</code></a> implementations,
which can be used to create a toolchain for working with optimized resources.</p>
</div>
<div class="paragraph">
<p>You can use the <code>VersionResourceResolver</code> for versioned resource URLs based on an MD5 hash
computed from the content, a fixed application version, or other information. A
<code>ContentVersionStrategy</code> (MD5 hash) is a good choice with some notable exceptions (such as
JavaScript resources used with a module loader).</p>
</div>
<div class="paragraph">
<p>The following example shows how to use <code>VersionResourceResolver</code> in your Java configuration:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    }

}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
    }

}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can use <code>ResourceUrlProvider</code> to rewrite URLs and apply the full chain of resolvers and
transformers (for example, to insert versions). The WebFlux configuration provides a <code>ResourceUrlProvider</code>
so that it can be injected into others.</p>
</div>
<div class="paragraph">
<p>Unlike Spring MVC, at present, in WebFlux, there is no way to transparently rewrite static
resource URLs, since there are no view technologies that can make use of a non-blocking chain
of resolvers and transformers. When serving only local resources, the workaround is to use
<code>ResourceUrlProvider</code> directly (for example, through a custom element) and block.</p>
</div>
<div class="paragraph">
<p>Note that, when using both <code>EncodedResourceResolver</code> (for example, Gzip, Brotli encoded) and
<code>VersionedResourceResolver</code>, they must be registered in that order, to ensure content-based
versions are always computed reliably based on the unencoded file.</p>
</div>
<div class="paragraph">
<p><a href="https://www.webjars.org/documentation">WebJars</a> are also supported through the
<code>WebJarsResourceResolver</code> which is automatically registered when the
<code>org.webjars:webjars-locator-core</code> library is present on the classpath. The resolver can
re-write URLs to include the version of the jar and can also match against incoming URLs
without versions&#8201;&#8212;&#8201;for example, from <code>/jquery/jquery.min.js</code> to
<code>/jquery/1.2.0/jquery.min.js</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-path-matching">1.11.9. Path Matching</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-path-matching">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>You can customize options related to path matching. For details on the individual options, see the
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/web/reactive/config/PathMatchConfigurer.html"><code>PathMatchConfigurer</code></a> javadoc.
The following example shows how to use <code>PathMatchConfigurer</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setUseCaseSensitiveMatch(true)
            .setUseTrailingSlashMatch(false)
            .addPathPrefix("/api",
                    HandlerTypePredicate.forAnnotation(RestController.class));
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Override
    fun configurePathMatch(configurer: PathMatchConfigurer) {
        configurer
            .setUseCaseSensitiveMatch(true)
            .setUseTrailingSlashMatch(false)
            .addPathPrefix("/api",
                    HandlerTypePredicate.forAnnotation(RestController::class.java))
    }
}</code></pre>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
<div class="paragraph">
<p>Spring WebFlux relies on a parsed representation of the request path called
<code>RequestPath</code> for access to decoded path segment values, with semicolon content removed
(that is, path or matrix variables). That means, unlike in Spring MVC, you need not indicate
whether to decode the request path nor whether to remove semicolon content for
path matching purposes.</p>
</div>
<div class="paragraph">
<p>Spring WebFlux also does not support suffix pattern matching, unlike in Spring MVC, where we
are also <a href="web.html#mvc-ann-requestmapping-suffix-pattern-match">recommend</a> moving away from
reliance on it.</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-websocket-service">1.11.10. WebSocketService</h4>
<div class="paragraph">
<p>The WebFlux Java config declares of a <code>WebSocketHandlerAdapter</code> bean which provides
support for the invocation of WebSocket handlers. That means all that remains to do in
order to handle a WebSocket handshake request is to map a <code>WebSocketHandler</code> to a URL
via <code>SimpleUrlHandlerMapping</code>.</p>
</div>
<div class="paragraph">
<p>In some cases it may be necessary to create the <code>WebSocketHandlerAdapter</code> bean with a
provided <code>WebSocketService</code> service which allows configuring WebSocket server properties.
For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {

    @Override
    public WebSocketService getWebSocketService() {
        TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
        strategy.setMaxSessionIdleTimeout(0L);
        return new HandshakeWebSocketService(strategy);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
@EnableWebFlux
class WebConfig : WebFluxConfigurer {

    @Override
    fun webSocketService(): WebSocketService {
        val strategy = TomcatRequestUpgradeStrategy().apply {
            setMaxSessionIdleTimeout(0L)
        }
        return HandshakeWebSocketService(strategy)
    }
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-config-advanced-java">1.11.11. Advanced Configuration Mode</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-config-advanced-java">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p><code>@EnableWebFlux</code> imports <code>DelegatingWebFluxConfiguration</code> that:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Provides default Spring configuration for WebFlux applications</p>
</li>
<li>
<p>detects and delegates to <code>WebFluxConfigurer</code> implementations to customize that configuration.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For advanced mode, you can remove <code>@EnableWebFlux</code> and extend directly from
<code>DelegatingWebFluxConfiguration</code> instead of implementing <code>WebFluxConfigurer</code>,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
public class WebConfig extends DelegatingWebFluxConfiguration {

    // ...
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class WebConfig : DelegatingWebFluxConfiguration {

    // ...
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can keep existing methods in <code>WebConfig</code>, but you can now also override bean declarations
from the base class and still have any number of other <code>WebMvcConfigurer</code> implementations on
the classpath.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-http2">1.12. HTTP/2</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#mvc-http2">Web MVC</a></span></p>
</div>
<div class="paragraph">
<p>HTTP/2 is supported with Reactor Netty, Tomcat, Jetty, and Undertow. However, there are
considerations related to server configuration. For more details, see the
<a href="https://github.com/spring-projects/spring-framework/wiki/HTTP-2-support">HTTP/2 wiki page</a>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="webflux-client">2. WebClient</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Spring WebFlux includes a client to perform HTTP requests with. <code>WebClient</code> has a
functional, fluent API based on Reactor, see <a href="web-reactive.html#webflux-reactive-libraries">web-reactive.html</a>,
which enables declarative composition of asynchronous logic without the need to deal with
threads or concurrency. It is fully non-blocking, it supports streaming, and relies on
the same <a href="web-reactive.html#webflux-codecs">codecs</a> that are also used to encode and
decode request and response content on the server side.</p>
</div>
<div class="paragraph">
<p><code>WebClient</code> needs an HTTP client library to perform requests with. There is built-in
support for the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/reactor/reactor-netty">Reactor Netty</a></p>
</li>
<li>
<p><a href="https://github.com/jetty-project/jetty-reactive-httpclient">Jetty Reactive HttpClient</a></p>
</li>
<li>
<p><a href="https://hc.apache.org/index.html">Apache HttpComponents</a></p>
</li>
<li>
<p>Others can be plugged via <code>ClientHttpConnector</code>.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="webflux-client-builder">2.1. Configuration</h3>
<div class="paragraph">
<p>The simplest way to create a <code>WebClient</code> is through one of the static factory methods:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>WebClient.create()</code></p>
</li>
<li>
<p><code>WebClient.create(String baseUrl)</code></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You can also use <code>WebClient.builder()</code> with further options:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>uriBuilderFactory</code>: Customized <code>UriBuilderFactory</code> to use as a base URL.</p>
</li>
<li>
<p><code>defaultUriVariables</code>: default values to use when expanding URI templates.</p>
</li>
<li>
<p><code>defaultHeader</code>: Headers for every request.</p>
</li>
<li>
<p><code>defaultCookie</code>: Cookies for every request.</p>
</li>
<li>
<p><code>defaultRequest</code>: <code>Consumer</code> to customize every request.</p>
</li>
<li>
<p><code>filter</code>: Client filter for every request.</p>
</li>
<li>
<p><code>exchangeStrategies</code>: HTTP message reader/writer customizations.</p>
</li>
<li>
<p><code>clientConnector</code>: HTTP client library settings.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client = WebClient.builder()
        .codecs(configurer -&gt; ... )
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val webClient = WebClient.builder()
        .codecs { configurer -&gt; ... }
        .build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Once built, a <code>WebClient</code> is immutable. However, you can clone it and build a
modified copy as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client1 = WebClient.builder()
        .filter(filterA).filter(filterB).build();

WebClient client2 = client1.mutate()
        .filter(filterC).filter(filterD).build();

// client1 has filterA, filterB

// client2 has filterA, filterB, filterC, filterD</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client1 = WebClient.builder()
        .filter(filterA).filter(filterB).build()

val client2 = client1.mutate()
        .filter(filterC).filter(filterD).build()

// client1 has filterA, filterB

// client2 has filterA, filterB, filterC, filterD</code></pre>
</div>
</div>
<div class="sect3">
<h4 id="webflux-client-builder-maxinmemorysize">2.1.1. MaxInMemorySize</h4>
<div class="paragraph">
<p>Codecs have <a href="web-reactive.html#webflux-codecs-limits">limits</a> for buffering data in
memory to avoid application memory issues. By the default those are set to 256KB.
If that&#8217;s not enough you&#8217;ll get the following error:</p>
</div>
<div class="listingblock">
<div class="content">
<pre>org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer</pre>
</div>
</div>
<div class="paragraph">
<p>To change the limit for default codecs, use the following:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient webClient = WebClient.builder()
        .codecs(configurer -&gt; configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024))
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val webClient = WebClient.builder()
        .codecs { configurer -&gt; configurer.defaultCodecs().maxInMemorySize(2 * 1024 * 1024) }
        .build()</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-client-builder-reactor">2.1.2. Reactor Netty</h4>
<div class="paragraph">
<p>To customize Reactor Netty settings, provide a pre-configured <code>HttpClient</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpClient httpClient = HttpClient.create().secure(sslSpec -&gt; ...);

WebClient webClient = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val httpClient = HttpClient.create().secure { ... }

val webClient = WebClient.builder()
    .clientConnector(ReactorClientHttpConnector(httpClient))
    .build()</code></pre>
</div>
</div>
<div class="sect4">
<h5 id="webflux-client-builder-reactor-resources">Resources</h5>
<div class="paragraph">
<p>By default, <code>HttpClient</code> participates in the global Reactor Netty resources held in
<code>reactor.netty.http.HttpResources</code>, including event loop threads and a connection pool.
This is the recommended mode, since fixed, shared resources are preferred for event loop
concurrency. In this mode global resources remain active until the process exits.</p>
</div>
<div class="paragraph">
<p>If the server is timed with the process, there is typically no need for an explicit
shutdown. However, if the server can start or stop in-process (for example, a Spring MVC
application deployed as a WAR), you can declare a Spring-managed bean of type
<code>ReactorResourceFactory</code> with <code>globalResources=true</code> (the default) to ensure that the Reactor
Netty global resources are shut down when the Spring <code>ApplicationContext</code> is closed,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Bean
public ReactorResourceFactory reactorResourceFactory() {
    return new ReactorResourceFactory();
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Bean
fun reactorResourceFactory() = ReactorResourceFactory()</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can also choose not to participate in the global Reactor Netty resources. However,
in this mode, the burden is on you to ensure that all Reactor Netty client and server
instances use shared resources, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Bean
public ReactorResourceFactory resourceFactory() {
    ReactorResourceFactory factory = new ReactorResourceFactory();
    factory.setUseGlobalResources(false); <i class="conum" data-value="1"></i><b>(1)</b>
    return factory;
}

@Bean
public WebClient webClient() {

    Function&lt;HttpClient, HttpClient&gt; mapper = client -&gt; {
        // Further customizations...
    };

    ClientHttpConnector connector =
            new ReactorClientHttpConnector(resourceFactory(), mapper); <i class="conum" data-value="2"></i><b>(2)</b>

    return WebClient.builder().clientConnector(connector).build(); <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Create resources independent of global ones.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Use the <code>ReactorClientHttpConnector</code> constructor with resource factory.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Plug the connector into the <code>WebClient.Builder</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Bean
fun resourceFactory() = ReactorResourceFactory().apply {
    isUseGlobalResources = false <i class="conum" data-value="1"></i><b>(1)</b>
}

@Bean
fun webClient(): WebClient {

    val mapper: (HttpClient) -&gt; HttpClient = {
        // Further customizations...
    }

    val connector = ReactorClientHttpConnector(resourceFactory(), mapper) <i class="conum" data-value="2"></i><b>(2)</b>

    return WebClient.builder().clientConnector(connector).build() <i class="conum" data-value="3"></i><b>(3)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Create resources independent of global ones.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Use the <code>ReactorClientHttpConnector</code> constructor with resource factory.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Plug the connector into the <code>WebClient.Builder</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect4">
<h5 id="webflux-client-builder-reactor-timeout">Timeouts</h5>
<div class="paragraph">
<p>To configure a connection timeout:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import io.netty.channel.ChannelOption;

HttpClient httpClient = HttpClient.create()
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);

WebClient webClient = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import io.netty.channel.ChannelOption

val httpClient = HttpClient.create()
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);

val webClient = WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();</code></pre>
</div>
</div>
<div class="paragraph">
<p>To configure a read or write timeout:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.handler.timeout.WriteTimeoutHandler;

HttpClient httpClient = HttpClient.create()
        .doOnConnected(conn -&gt; conn
                .addHandlerLast(new ReadTimeoutHandler(10))
                .addHandlerLast(new WriteTimeoutHandler(10)));

// Create WebClient...</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import io.netty.handler.timeout.ReadTimeoutHandler
import io.netty.handler.timeout.WriteTimeoutHandler

val httpClient = HttpClient.create()
        .doOnConnected { conn -&gt; conn
                .addHandlerLast(new ReadTimeoutHandler(10))
                .addHandlerLast(new WriteTimeoutHandler(10))
        }

// Create WebClient...</code></pre>
</div>
</div>
<div class="paragraph">
<p>To configure a response timeout for all requests:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpClient httpClient = HttpClient.create()
        .responseTimeout(Duration.ofSeconds(2));

// Create WebClient...</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val httpClient = HttpClient.create()
        .responseTimeout(Duration.ofSeconds(2));

// Create WebClient...</code></pre>
</div>
</div>
<div class="paragraph">
<p>To configure a response timeout for a specific request:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient.create().get()
        .uri("https://example.org/path")
        .httpRequest(httpRequest -&gt; {
            HttpClientRequest reactorRequest = httpRequest.getNativeRequest();
            reactorRequest.responseTimeout(Duration.ofSeconds(2));
        })
        .retrieve()
        .bodyToMono(String.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">WebClient.create().get()
        .uri("https://example.org/path")
        .httpRequest { httpRequest: ClientHttpRequest -&gt;
            val reactorRequest = httpRequest.getNativeRequest&lt;HttpClientRequest&gt;()
            reactorRequest.responseTimeout(Duration.ofSeconds(2))
        }
        .retrieve()
        .bodyToMono(String::class.java)</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-client-builder-jetty">2.1.3. Jetty</h4>
<div class="paragraph">
<p>The following example shows how to customize Jetty <code>HttpClient</code> settings:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpClient httpClient = new HttpClient();
httpClient.setCookieStore(...);

WebClient webClient = WebClient.builder()
        .clientConnector(new JettyClientHttpConnector(httpClient))
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val httpClient = HttpClient()
httpClient.cookieStore = ...

val webClient = WebClient.builder()
        .clientConnector(new JettyClientHttpConnector(httpClient))
        .build();</code></pre>
</div>
</div>
<div class="paragraph">
<p>By default, <code>HttpClient</code> creates its own resources (<code>Executor</code>, <code>ByteBufferPool</code>, <code>Scheduler</code>),
which remain active until the process exits or <code>stop()</code> is called.</p>
</div>
<div class="paragraph">
<p>You can share resources between multiple instances of the Jetty client (and server) and
ensure that the resources are shut down when the Spring <code>ApplicationContext</code> is closed by
declaring a Spring-managed bean of type <code>JettyResourceFactory</code>, as the following example
shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Bean
public JettyResourceFactory resourceFactory() {
    return new JettyResourceFactory();
}

@Bean
public WebClient webClient() {

    HttpClient httpClient = new HttpClient();
    // Further customizations...

    ClientHttpConnector connector =
            new JettyClientHttpConnector(httpClient, resourceFactory()); <i class="conum" data-value="1"></i><b>(1)</b>

    return WebClient.builder().clientConnector(connector).build(); <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Use the <code>JettyClientHttpConnector</code> constructor with resource factory.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Plug the connector into the <code>WebClient.Builder</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Bean
fun resourceFactory() = JettyResourceFactory()

@Bean
fun webClient(): WebClient {

    val httpClient = HttpClient()
    // Further customizations...

    val connector = JettyClientHttpConnector(httpClient, resourceFactory()) <i class="conum" data-value="1"></i><b>(1)</b>

    return WebClient.builder().clientConnector(connector).build() <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Use the <code>JettyClientHttpConnector</code> constructor with resource factory.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Plug the connector into the <code>WebClient.Builder</code>.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-client-builder-http-components">2.1.4. HttpComponents</h4>
<div class="paragraph">
<p>The following example shows how to customize Apache HttpComponents <code>HttpClient</code> settings:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">HttpAsyncClientBuilder clientBuilder = HttpAsyncClients.custom();
clientBuilder.setDefaultRequestConfig(...);
CloseableHttpAsyncClient client = clientBuilder.build();
ClientHttpConnector connector = new HttpComponentsClientHttpConnector(client);

WebClient webClient = WebClient.builder().clientConnector(connector).build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = HttpAsyncClients.custom().apply {
    setDefaultRequestConfig(...)
}.build()
val connector = HttpComponentsClientHttpConnector(client)
val webClient = WebClient.builder().clientConnector(connector).build()</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-retrieve">2.2. <code>retrieve()</code></h3>
<div class="paragraph">
<p>The <code>retrieve()</code> method can be used to declare how to extract the response. For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client = WebClient.create("https://example.org");

Mono&lt;ResponseEntity&lt;Person&gt;&gt; result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .toEntity(Person.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = WebClient.create("https://example.org")

val result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .toEntity&lt;Person&gt;().awaitSingle()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Or to get only the body:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client = WebClient.create("https://example.org");

Mono&lt;Person&gt; result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .bodyToMono(Person.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = WebClient.create("https://example.org")

val result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .awaitBody&lt;Person&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>To get a stream of decoded objects:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Flux&lt;Quote&gt; result = client.get()
        .uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
        .retrieve()
        .bodyToFlux(Quote.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val result = client.get()
        .uri("/quotes").accept(MediaType.TEXT_EVENT_STREAM)
        .retrieve()
        .bodyToFlow&lt;Quote&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>By default, 4xx or 5xx responses result in an <code>WebClientResponseException</code>, including
sub-classes for specific HTTP status codes. To customize the handling of error
responses, use <code>onStatus</code> handlers as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;Person&gt; result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .onStatus(HttpStatus::is4xxClientError, response -&gt; ...)
        .onStatus(HttpStatus::is5xxServerError, response -&gt; ...)
        .bodyToMono(Person.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val result = client.get()
        .uri("/persons/{id}", id).accept(MediaType.APPLICATION_JSON)
        .retrieve()
        .onStatus(HttpStatus::is4xxClientError) { ... }
        .onStatus(HttpStatus::is5xxServerError) { ... }
        .awaitBody&lt;Person&gt;()</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-exchange">2.3. Exchange</h3>
<div class="paragraph">
<p>The <code>exchangeToMono()</code> and <code>exchangeToFlux()</code> methods (or <code>awaitExchange { }</code> and <code>exchangeToFlow { }</code> in Kotlin)
are useful for more advanced cases that require more control, such as to decode the response differently
depending on the response status:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;Object&gt; entityMono = client.get()
        .uri("/persons/1")
        .accept(MediaType.APPLICATION_JSON)
        .exchangeToMono(response -&gt; {
            if (response.statusCode().equals(HttpStatus.OK)) {
                return response.bodyToMono(Person.class);
            }
            else if (response.statusCode().is4xxClientError()) {
                // Suppress error status code
                return response.bodyToMono(ErrorContainer.class);
            }
            else {
                // Turn to error
                return response.createException().flatMap(Mono::error);
            }
        });</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val entity = client.get()
  .uri("/persons/1")
  .accept(MediaType.APPLICATION_JSON)
  .awaitExchange {
        if (response.statusCode() == HttpStatus.OK) {
             return response.awaitBody&lt;Person&gt;()
        }
        else if (response.statusCode().is4xxClientError) {
             return response.awaitBody&lt;ErrorContainer&gt;()
        }
        else {
             throw response.createExceptionAndAwait()
        }
  }</code></pre>
</div>
</div>
<div class="paragraph">
<p>When using the above, after the returned <code>Mono</code> or <code>Flux</code> completes, the response body
is checked and if not consumed it is released to prevent memory and connection leaks.
Therefore the response cannot be decoded further downstream. It is up to the provided
function to declare how to decode the response if needed.</p>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-body">2.4. Request Body</h3>
<div class="paragraph">
<p>The request body can be encoded from any asynchronous type handled by <code>ReactiveAdapterRegistry</code>,
like <code>Mono</code> or Kotlin Coroutines <code>Deferred</code> as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;Person&gt; personMono = ... ;

Mono&lt;Void&gt; result = client.post()
        .uri("/persons/{id}", id)
        .contentType(MediaType.APPLICATION_JSON)
        .body(personMono, Person.class)
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val personDeferred: Deferred&lt;Person&gt; = ...

client.post()
        .uri("/persons/{id}", id)
        .contentType(MediaType.APPLICATION_JSON)
        .body&lt;Person&gt;(personDeferred)
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can also have a stream of objects be encoded, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Flux&lt;Person&gt; personFlux = ... ;

Mono&lt;Void&gt; result = client.post()
        .uri("/persons/{id}", id)
        .contentType(MediaType.APPLICATION_STREAM_JSON)
        .body(personFlux, Person.class)
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val people: Flow&lt;Person&gt; = ...

client.post()
        .uri("/persons/{id}", id)
        .contentType(MediaType.APPLICATION_JSON)
        .body(people)
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Alternatively, if you have the actual value, you can use the <code>bodyValue</code> shortcut method,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Person person = ... ;

Mono&lt;Void&gt; result = client.post()
        .uri("/persons/{id}", id)
        .contentType(MediaType.APPLICATION_JSON)
        .bodyValue(person)
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val person: Person = ...

client.post()
        .uri("/persons/{id}", id)
        .contentType(MediaType.APPLICATION_JSON)
        .bodyValue(person)
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
<div class="sect3">
<h4 id="webflux-client-body-form">2.4.1. Form Data</h4>
<div class="paragraph">
<p>To send form data, you can provide a <code>MultiValueMap&lt;String, String&gt;</code> as the body. Note that the
content is automatically set to <code>application/x-www-form-urlencoded</code> by the
<code>FormHttpMessageWriter</code>. The following example shows how to use <code>MultiValueMap&lt;String, String&gt;</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">MultiValueMap&lt;String, String&gt; formData = ... ;

Mono&lt;Void&gt; result = client.post()
        .uri("/path", id)
        .bodyValue(formData)
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val formData: MultiValueMap&lt;String, String&gt; = ...

client.post()
        .uri("/path", id)
        .bodyValue(formData)
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can also supply form data in-line by using <code>BodyInserters</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.web.reactive.function.BodyInserters.*;

Mono&lt;Void&gt; result = client.post()
        .uri("/path", id)
        .body(fromFormData("k1", "v1").with("k2", "v2"))
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.web.reactive.function.BodyInserters.*

client.post()
        .uri("/path", id)
        .body(fromFormData("k1", "v1").with("k2", "v2"))
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-client-body-multipart">2.4.2. Multipart Data</h4>
<div class="paragraph">
<p>To send multipart data, you need to provide a <code>MultiValueMap&lt;String, ?&gt;</code> whose values are
either <code>Object</code> instances that represent part content or <code>HttpEntity</code> instances that represent the content and
headers for a part. <code>MultipartBodyBuilder</code> provides a convenient API to prepare a
multipart request. The following example shows how to create a <code>MultiValueMap&lt;String, ?&gt;</code>:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("fieldPart", "fieldValue");
builder.part("filePart1", new FileSystemResource("...logo.png"));
builder.part("jsonPart", new Person("Jason"));
builder.part("myPart", part); // Part from a server request

MultiValueMap&lt;String, HttpEntity&lt;?&gt;&gt; parts = builder.build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val builder = MultipartBodyBuilder().apply {
    part("fieldPart", "fieldValue")
    part("filePart1", new FileSystemResource("...logo.png"))
    part("jsonPart", new Person("Jason"))
    part("myPart", part) // Part from a server request
}

val parts = builder.build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>In most cases, you do not have to specify the <code>Content-Type</code> for each part. The content
type is determined automatically based on the <code>HttpMessageWriter</code> chosen to serialize it
or, in the case of a <code>Resource</code>, based on the file extension. If necessary, you can
explicitly provide the <code>MediaType</code> to use for each part through one of the overloaded
builder <code>part</code> methods.</p>
</div>
<div class="paragraph">
<p>Once a <code>MultiValueMap</code> is prepared, the easiest way to pass it to the <code>WebClient</code> is
through the <code>body</code> method, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">MultipartBodyBuilder builder = ...;

Mono&lt;Void&gt; result = client.post()
        .uri("/path", id)
        .body(builder.build())
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val builder: MultipartBodyBuilder = ...

client.post()
        .uri("/path", id)
        .body(builder.build())
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>If the <code>MultiValueMap</code> contains at least one non-<code>String</code> value, which could also
represent regular form data (that is, <code>application/x-www-form-urlencoded</code>), you need not
set the <code>Content-Type</code> to <code>multipart/form-data</code>. This is always the case when using
<code>MultipartBodyBuilder</code>, which ensures an <code>HttpEntity</code> wrapper.</p>
</div>
<div class="paragraph">
<p>As an alternative to <code>MultipartBodyBuilder</code>, you can also provide multipart content,
inline-style, through the built-in <code>BodyInserters</code>, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.web.reactive.function.BodyInserters.*;

Mono&lt;Void&gt; result = client.post()
        .uri("/path", id)
        .body(fromMultipartData("fieldPart", "value").with("filePart", resource))
        .retrieve()
        .bodyToMono(Void.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.web.reactive.function.BodyInserters.*

client.post()
        .uri("/path", id)
        .body(fromMultipartData("fieldPart", "value").with("filePart", resource))
        .retrieve()
        .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-filter">2.5. Filters</h3>
<div class="paragraph">
<p>You can register a client filter (<code>ExchangeFilterFunction</code>) through the <code>WebClient.Builder</code>
in order to intercept and modify requests, as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client = WebClient.builder()
        .filter((request, next) -&gt; {

            ClientRequest filtered = ClientRequest.from(request)
                    .header("foo", "bar")
                    .build();

            return next.exchange(filtered);
        })
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = WebClient.builder()
        .filter { request, next -&gt;

            val filtered = ClientRequest.from(request)
                    .header("foo", "bar")
                    .build()

            next.exchange(filtered)
        }
        .build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>This can be used for cross-cutting concerns, such as authentication. The following example uses
a filter for basic authentication through a static factory method:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;

WebClient client = WebClient.builder()
        .filter(basicAuthentication("user", "password"))
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication

val client = WebClient.builder()
        .filter(basicAuthentication("user", "password"))
        .build()</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can create a new <code>WebClient</code> instance by using another as a starting point. This allows
insert or removing filters without affecting the original <code>WebClient</code>. Below is an example
that inserts a basic authentication filter at index 0:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;

WebClient client = webClient.mutate()
        .filters(filterList -&gt; {
            filterList.add(0, basicAuthentication("user", "password"));
        })
        .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = webClient.mutate()
        .filters { it.add(0, basicAuthentication("user", "password")) }
        .build()</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-attributes">2.6. Attributes</h3>
<div class="paragraph">
<p>You can add attributes to a request. This is convenient if you want to pass information
through the filter chain and influence the behavior of filters for a given request.
For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client = WebClient.builder()
        .filter((request, next) -&gt; {
            Optional&lt;Object&gt; usr = request.attribute("myAttribute");
            // ...
        })
        .build();

client.get().uri("https://example.org/")
        .attribute("myAttribute", "...")
        .retrieve()
        .bodyToMono(Void.class);

    }</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = WebClient.builder()
        .filter { request, _ -&gt;
            val usr = request.attributes()["myAttribute"];
            // ...
        }
        .build()

    client.get().uri("https://example.org/")
            .attribute("myAttribute", "...")
            .retrieve()
            .awaitBody&lt;Unit&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Note that you can configure a <code>defaultRequest</code> callback globally at the
<code>WebClient.Builder</code> level which lets you insert attributes into all requests,
which could be used for example in a Spring MVC application to populate
request attributes based on <code>ThreadLocal</code> data.</p>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-context">2.7. Context</h3>
<div class="paragraph">
<p><a href="#webflux-client-attributes">Attributes</a> provide a convenient way to pass information to the filter
chain but they only influence the current request. If you want to pass information that
propagates to additional requests that are nested, e.g. via <code>flatMap</code>, or executed after,
e.g. via <code>concatMap</code>, then you&#8217;ll need to use the Reactor <code>Context</code>.</p>
</div>
<div class="paragraph">
<p>The Reactor <code>Context</code> needs to be populated at the end of a reactive chain in order to
apply to all operations. For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebClient client = WebClient.builder()
        .filter((request, next) -&gt;
                Mono.deferContextual(contextView -&gt; {
                    String value = contextView.get("foo");
                    // ...
                }))
        .build();

client.get().uri("https://example.org/")
        .retrieve()
        .bodyToMono(String.class)
        .flatMap(body -&gt; {
                // perform nested request (context propagates automatically)...
        })
        .contextWrite(context -&gt; context.put("foo", ...));</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-synchronous">2.8. Synchronous Use</h3>
<div class="paragraph">
<p><code>WebClient</code> can be used in synchronous style by blocking at the end for the result:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Person person = client.get().uri("/person/{id}", i).retrieve()
    .bodyToMono(Person.class)
    .block();

List&lt;Person&gt; persons = client.get().uri("/persons").retrieve()
    .bodyToFlux(Person.class)
    .collectList()
    .block();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val person = runBlocking {
    client.get().uri("/person/{id}", i).retrieve()
            .awaitBody&lt;Person&gt;()
}

val persons = runBlocking {
    client.get().uri("/persons").retrieve()
            .bodyToFlow&lt;Person&gt;()
            .toList()
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>However if multiple calls need to be made, it&#8217;s more efficient to avoid blocking on each
response individually, and instead wait for the combined result:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;Person&gt; personMono = client.get().uri("/person/{id}", personId)
        .retrieve().bodyToMono(Person.class);

Mono&lt;List&lt;Hobby&gt;&gt; hobbiesMono = client.get().uri("/person/{id}/hobbies", personId)
        .retrieve().bodyToFlux(Hobby.class).collectList();

Map&lt;String, Object&gt; data = Mono.zip(personMono, hobbiesMono, (person, hobbies) -&gt; {
            Map&lt;String, String&gt; map = new LinkedHashMap&lt;&gt;();
            map.put("person", person);
            map.put("hobbies", hobbies);
            return map;
        })
        .block();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val data = runBlocking {
        val personDeferred = async {
            client.get().uri("/person/{id}", personId)
                    .retrieve().awaitBody&lt;Person&gt;()
        }

        val hobbiesDeferred = async {
            client.get().uri("/person/{id}/hobbies", personId)
                    .retrieve().bodyToFlow&lt;Hobby&gt;().toList()
        }

        mapOf("person" to personDeferred.await(), "hobbies" to hobbiesDeferred.await())
    }</code></pre>
</div>
</div>
<div class="paragraph">
<p>The above is merely one example. There are lots of other patterns and operators for putting
together a reactive pipeline that makes many remote calls, potentially some nested,
inter-dependent, without ever blocking until the end.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>With <code>Flux</code> or <code>Mono</code>, you should never have to block in a Spring MVC or Spring WebFlux controller.
Simply return the resulting reactive type from the controller method. The same principle apply to
Kotlin Coroutines and Spring WebFlux, just use suspending function or return <code>Flow</code> in your
controller method .</p>
</div>
</td>
</tr>
</table>
</div>
</div>
<div class="sect2">
<h3 id="webflux-client-testing">2.9. Testing</h3>
<div class="paragraph">
<p>To test code that uses the <code>WebClient</code>, you can use a mock web server, such as the
<a href="https://github.com/square/okhttp#mockwebserver">OkHttp MockWebServer</a>. To see an example
of its use, check out
<a href="https://github.com/spring-projects/spring-framework/blob/master/spring-webflux/src/test/java/org/springframework/web/reactive/function/client/WebClientIntegrationTests.java"><code>WebClientIntegrationTests</code></a>
in the Spring Framework test suite or the
<a href="https://github.com/square/okhttp/tree/master/samples/static-server"><code>static-server</code></a>
sample in the OkHttp repository.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="webflux-websocket">3. WebSockets</h2>
<div class="sectionbody">
<div class="paragraph">
<p><span class="small"><a href="web.html#websocket">Same as in the Servlet stack</a></span></p>
</div>
<div class="paragraph">
<p>This part of the reference documentation covers support for reactive-stack WebSocket
messaging.</p>
</div>
<div class="sect2">
<h3 id="websocket-intro">3.1. Introduction to WebSocket</h3>
<div class="paragraph">
<p>The WebSocket protocol, <a href="https://tools.ietf.org/html/rfc6455">RFC 6455</a>, provides a standardized
way to establish a full-duplex, two-way communication channel between client and server
over a single TCP connection. It is a different TCP protocol from HTTP but is designed to
work over HTTP, using ports 80 and 443 and allowing re-use of existing firewall rules.</p>
</div>
<div class="paragraph">
<p>A WebSocket interaction begins with an HTTP request that uses the HTTP <code>Upgrade</code> header
to upgrade or, in this case, to switch to the WebSocket protocol. The following example
shows such an interaction:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="yaml">GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket <i class="conum" data-value="1"></i><b>(1)</b>
Connection: Upgrade <i class="conum" data-value="2"></i><b>(2)</b>
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>The <code>Upgrade</code> header.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Using the <code>Upgrade</code> connection.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Instead of the usual 200 status code, a server with WebSocket support returns output
similar to the following:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="yaml">HTTP/1.1 101 Switching Protocols <i class="conum" data-value="1"></i><b>(1)</b>
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Protocol switch</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>After a successful handshake, the TCP socket underlying the HTTP upgrade request remains
open for both the client and the server to continue to send and receive messages.</p>
</div>
<div class="paragraph">
<p>A complete introduction of how WebSockets work is beyond the scope of this document.
See RFC 6455, the WebSocket chapter of HTML5, or any of the many introductions and
tutorials on the Web.</p>
</div>
<div class="paragraph">
<p>Note that, if a WebSocket server is running behind a web server (e.g. nginx), you
likely need to configure it to pass WebSocket upgrade requests on to the WebSocket
server. Likewise, if the application runs in a cloud environment, check the
instructions of the cloud provider related to WebSocket support.</p>
</div>
<div class="sect3">
<h4 id="websocket-intro-architecture">3.1.1. HTTP Versus WebSocket</h4>
<div class="paragraph">
<p>Even though WebSocket is designed to be HTTP-compatible and starts with an HTTP request,
it is important to understand that the two protocols lead to very different
architectures and application programming models.</p>
</div>
<div class="paragraph">
<p>In HTTP and REST, an application is modeled as many URLs. To interact with the application,
clients access those URLs, request-response style. Servers route requests to the
appropriate handler based on the HTTP URL, method, and headers.</p>
</div>
<div class="paragraph">
<p>By contrast, in WebSockets, there is usually only one URL for the initial connect.
Subsequently, all application messages flow on that same TCP connection. This points to
an entirely different asynchronous, event-driven, messaging architecture.</p>
</div>
<div class="paragraph">
<p>WebSocket is also a low-level transport protocol, which, unlike HTTP, does not prescribe
any semantics to the content of messages. That means that there is no way to route or process
a message unless the client and the server agree on message semantics.</p>
</div>
<div class="paragraph">
<p>WebSocket clients and servers can negotiate the use of a higher-level, messaging protocol
(for example, STOMP), through the <code>Sec-WebSocket-Protocol</code> header on the HTTP handshake request.
In the absence of that, they need to come up with their own conventions.</p>
</div>
</div>
<div class="sect3">
<h4 id="websocket-intro-when-to-use">3.1.2. When to Use WebSockets</h4>
<div class="paragraph">
<p>WebSockets can make a web page be dynamic and interactive. However, in many cases,
a combination of Ajax and HTTP streaming or long polling can provide a simple and
effective solution.</p>
</div>
<div class="paragraph">
<p>For example, news, mail, and social feeds need to update dynamically, but it may be
perfectly okay to do so every few minutes. Collaboration, games, and financial apps, on
the other hand, need to be much closer to real-time.</p>
</div>
<div class="paragraph">
<p>Latency alone is not a deciding factor. If the volume of messages is relatively low (for example,
monitoring network failures) HTTP streaming or polling can provide an effective solution.
It is the combination of low latency, high frequency, and high volume that make the best
case for the use of WebSocket.</p>
</div>
<div class="paragraph">
<p>Keep in mind also that over the Internet, restrictive proxies that are outside of your control
may preclude WebSocket interactions, either because they are not configured to pass on the
<code>Upgrade</code> header or because they close long-lived connections that appear idle. This
means that the use of WebSocket for internal applications within the firewall is a more
straightforward decision than it is for public facing applications.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="webflux-websocket-server">3.2. WebSocket API</h3>
<div class="paragraph">
<p><span class="small"><a href="web.html#websocket-server">Same as in the Servlet stack</a></span></p>
</div>
<div class="paragraph">
<p>The Spring Framework provides a WebSocket API that you can use to write client- and
server-side applications that handle WebSocket messages.</p>
</div>
<div class="sect3">
<h4 id="webflux-websocket-server-handler">3.2.1. Server</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#websocket-server-handler">Same as in the Servlet stack</a></span></p>
</div>
<div class="paragraph">
<p>To create a WebSocket server, you can first create a <code>WebSocketHandler</code>.
The following example shows how to do so:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">import org.springframework.web.reactive.socket.WebSocketHandler;
import org.springframework.web.reactive.socket.WebSocketSession;

public class MyWebSocketHandler implements WebSocketHandler {

    @Override
    public Mono&lt;Void&gt; handle(WebSocketSession session) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.web.reactive.socket.WebSocketHandler
import org.springframework.web.reactive.socket.WebSocketSession

class MyWebSocketHandler : WebSocketHandler {

    override fun handle(session: WebSocketSession): Mono&lt;Void&gt; {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then you can map it to a URL:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
class WebConfig {

    @Bean
    public HandlerMapping handlerMapping() {
        Map&lt;String, WebSocketHandler&gt; map = new HashMap&lt;&gt;();
        map.put("/path", new MyWebSocketHandler());
        int order = -1; // before annotated controllers

        return new SimpleUrlHandlerMapping(map, order);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class WebConfig {

    @Bean
    fun handlerMapping(): HandlerMapping {
        val map = mapOf("/path" to MyWebSocketHandler())
        val order = -1 // before annotated controllers

        return SimpleUrlHandlerMapping(map, order)
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>If using the <a href="web-reactive.html#webflux-config">WebFlux Config</a> there is nothing
further to do, or otherwise if not using the WebFlux config you&#8217;ll need to declare a
<code>WebSocketHandlerAdapter</code> as shown below:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
class WebConfig {

    // ...

    @Bean
    public WebSocketHandlerAdapter handlerAdapter() {
        return new WebSocketHandlerAdapter();
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class WebConfig {

    // ...

    @Bean
    fun handlerAdapter() =  WebSocketHandlerAdapter()
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="webflux-websockethandler">3.2.2. <code>WebSocketHandler</code></h4>
<div class="paragraph">
<p>The <code>handle</code> method of <code>WebSocketHandler</code> takes <code>WebSocketSession</code> and returns <code>Mono&lt;Void&gt;</code>
to indicate when application handling of the session is complete. The session is handled
through two streams, one for inbound and one for outbound messages. The following table
describes the two methods that handle the streams:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 50%;">
<col style="width: 50%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top"><code>WebSocketSession</code> method</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Flux&lt;WebSocketMessage&gt; receive()</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Provides access to the inbound message stream and completes when the connection is closed.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>Mono&lt;Void&gt; send(Publisher&lt;WebSocketMessage&gt;)</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Takes a source for outgoing messages, writes the messages, and returns a <code>Mono&lt;Void&gt;</code> that
  completes when the source completes and writing is done.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>A <code>WebSocketHandler</code> must compose the inbound and outbound streams into a unified flow and
return a <code>Mono&lt;Void&gt;</code> that reflects the completion of that flow. Depending on application
requirements, the unified flow completes when:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Either the inbound or the outbound message stream completes.</p>
</li>
<li>
<p>The inbound stream completes (that is, the connection closed), while the outbound stream is infinite.</p>
</li>
<li>
<p>At a chosen point, through the <code>close</code> method of <code>WebSocketSession</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>When inbound and outbound message streams are composed together, there is no need to
check if the connection is open, since Reactive Streams signals end activity.
The inbound stream receives a completion or error signal, and the outbound stream
receives a cancellation signal.</p>
</div>
<div class="paragraph">
<p>The most basic implementation of a handler is one that handles the inbound stream. The
following example shows such an implementation:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">class ExampleHandler implements WebSocketHandler {

    @Override
    public Mono&lt;Void&gt; handle(WebSocketSession session) {
        return session.receive()            <i class="conum" data-value="1"></i><b>(1)</b>
                .doOnNext(message -&gt; {
                    // ...                  <i class="conum" data-value="2"></i><b>(2)</b>
                })
                .concatMap(message -&gt; {
                    // ...                  <i class="conum" data-value="3"></i><b>(3)</b>
                })
                .then();                    <i class="conum" data-value="4"></i><b>(4)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Access the stream of inbound messages.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Do something with each message.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Perform nested asynchronous operations that use the message content.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Return a <code>Mono&lt;Void&gt;</code> that completes when receiving completes.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">class ExampleHandler : WebSocketHandler {

    override fun handle(session: WebSocketSession): Mono&lt;Void&gt; {
        return session.receive()            <i class="conum" data-value="1"></i><b>(1)</b>
                .doOnNext {
                    // ...                  <i class="conum" data-value="2"></i><b>(2)</b>
                }
                .concatMap {
                    // ...                  <i class="conum" data-value="3"></i><b>(3)</b>
                }
                .then()                     <i class="conum" data-value="4"></i><b>(4)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Access the stream of inbound messages.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Do something with each message.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Perform nested asynchronous operations that use the message content.</td>
</tr>
<tr>
<td><i class="conum" data-value="4"></i><b>4</b></td>
<td>Return a <code>Mono&lt;Void&gt;</code> that completes when receiving completes.</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
For nested, asynchronous operations, you may need to call <code>message.retain()</code> on underlying
servers that use pooled data buffers (for example, Netty). Otherwise, the data buffer may be
released before you have had a chance to read the data. For more background, see
<a href="core.html#databuffers">Data Buffers and Codecs</a>.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The following implementation combines the inbound and outbound streams:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">class ExampleHandler implements WebSocketHandler {

    @Override
    public Mono&lt;Void&gt; handle(WebSocketSession session) {

        Flux&lt;WebSocketMessage&gt; output = session.receive()               <i class="conum" data-value="1"></i><b>(1)</b>
                .doOnNext(message -&gt; {
                    // ...
                })
                .concatMap(message -&gt; {
                    // ...
                })
                .map(value -&gt; session.textMessage("Echo " + value));    <i class="conum" data-value="2"></i><b>(2)</b>

        return session.send(output);                                    <i class="conum" data-value="3"></i><b>(3)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Handle the inbound message stream.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Create the outbound message, producing a combined flow.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Return a <code>Mono&lt;Void&gt;</code> that does not complete while we continue to receive.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">class ExampleHandler : WebSocketHandler {

    override fun handle(session: WebSocketSession): Mono&lt;Void&gt; {

        val output = session.receive()                      <i class="conum" data-value="1"></i><b>(1)</b>
                .doOnNext {
                    // ...
                }
                .concatMap {
                    // ...
                }
                .map { session.textMessage("Echo $it") }    <i class="conum" data-value="2"></i><b>(2)</b>

        return session.send(output)                         <i class="conum" data-value="3"></i><b>(3)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Handle the inbound message stream.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Create the outbound message, producing a combined flow.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Return a <code>Mono&lt;Void&gt;</code> that does not complete while we continue to receive.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Inbound and outbound streams can be independent and be joined only for completion,
as the following example shows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">class ExampleHandler implements WebSocketHandler {

    @Override
    public Mono&lt;Void&gt; handle(WebSocketSession session) {

        Mono&lt;Void&gt; input = session.receive()                                <i class="conum" data-value="1"></i><b>(1)</b>
                .doOnNext(message -&gt; {
                    // ...
                })
                .concatMap(message -&gt; {
                    // ...
                })
                .then();

        Flux&lt;String&gt; source = ... ;
        Mono&lt;Void&gt; output = session.send(source.map(session::textMessage)); <i class="conum" data-value="2"></i><b>(2)</b>

        return Mono.zip(input, output).then();                              <i class="conum" data-value="3"></i><b>(3)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Handle inbound message stream.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Send outgoing messages.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Join the streams and return a <code>Mono&lt;Void&gt;</code> that completes when either stream ends.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">class ExampleHandler : WebSocketHandler {

    override fun handle(session: WebSocketSession): Mono&lt;Void&gt; {

        val input = session.receive()                                   <i class="conum" data-value="1"></i><b>(1)</b>
                .doOnNext {
                    // ...
                }
                .concatMap {
                    // ...
                }
                .then()

        val source: Flux&lt;String&gt; = ...
        val output = session.send(source.map(session::textMessage))     <i class="conum" data-value="2"></i><b>(2)</b>

        return Mono.zip(input, output).then()                           <i class="conum" data-value="3"></i><b>(3)</b>
    }
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Handle inbound message stream.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Send outgoing messages.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Join the streams and return a <code>Mono&lt;Void&gt;</code> that completes when either stream ends.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="webflux-websocket-databuffer">3.2.3. <code>DataBuffer</code></h4>
<div class="paragraph">
<p><code>DataBuffer</code> is the representation for a byte buffer in WebFlux. The Spring Core part of
the reference has more on that in the section on
<a href="core.html#databuffers">Data Buffers and Codecs</a>. The key point to understand is that on some
servers like Netty, byte buffers are pooled and reference counted, and must be released
when consumed to avoid memory leaks.</p>
</div>
<div class="paragraph">
<p>When running on Netty, applications must use <code>DataBufferUtils.retain(dataBuffer)</code> if they
wish to hold on input data buffers in order to ensure they are not released, and
subsequently use <code>DataBufferUtils.release(dataBuffer)</code> when the buffers are consumed.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-websocket-server-handshake">3.2.4. Handshake</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#websocket-server-handshake">Same as in the Servlet stack</a></span></p>
</div>
<div class="paragraph">
<p><code>WebSocketHandlerAdapter</code> delegates to a <code>WebSocketService</code>. By default, that is an instance
of <code>HandshakeWebSocketService</code>, which performs basic checks on the WebSocket request and
then uses <code>RequestUpgradeStrategy</code> for the server in use. Currently, there is built-in
support for Reactor Netty, Tomcat, Jetty, and Undertow.</p>
</div>
<div class="paragraph">
<p><code>HandshakeWebSocketService</code> exposes a <code>sessionAttributePredicate</code> property that allows
setting a <code>Predicate&lt;String&gt;</code> to extract attributes from the <code>WebSession</code> and insert them
into the attributes of the <code>WebSocketSession</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-websocket-server-config">3.2.5. Server Configation</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#websocket-server-runtime-configuration">Same as in the Servlet stack</a></span></p>
</div>
<div class="paragraph">
<p>The <code>RequestUpgradeStrategy</code> for each server exposes configuration specific to the
underlying WebSocket server engine. When using the WebFlux Java config you can customize
such properties as shown in the corresponding section of the
<a href="web-reactive.html#webflux-config-websocket-service">WebFlux Config</a>, or otherwise if
not using the WebFlux config, use the below:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
class WebConfig {

    @Bean
    public WebSocketHandlerAdapter handlerAdapter() {
        return new WebSocketHandlerAdapter(webSocketService());
    }

    @Bean
    public WebSocketService webSocketService() {
        TomcatRequestUpgradeStrategy strategy = new TomcatRequestUpgradeStrategy();
        strategy.setMaxSessionIdleTimeout(0L);
        return new HandshakeWebSocketService(strategy);
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class WebConfig {

    @Bean
    fun handlerAdapter() =
            WebSocketHandlerAdapter(webSocketService())

    @Bean
    fun webSocketService(): WebSocketService {
        val strategy = TomcatRequestUpgradeStrategy().apply {
            setMaxSessionIdleTimeout(0L)
        }
        return HandshakeWebSocketService(strategy)
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Check the upgrade strategy for your server to see what options are available. Currently,
only Tomcat and Jetty expose such options.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-websocket-server-cors">3.2.6. CORS</h4>
<div class="paragraph">
<p><span class="small"><a href="web.html#websocket-server-allowed-origins">Same as in the Servlet stack</a></span></p>
</div>
<div class="paragraph">
<p>The easiest way to configure CORS and restrict access to a WebSocket endpoint is to
have your <code>WebSocketHandler</code> implement <code>CorsConfigurationSource</code> and return a
<code>CorsConfiguration</code> with allowed origins, headers, and other details. If you cannot do
that, you can also set the <code>corsConfigurations</code> property on the <code>SimpleUrlHandler</code> to
specify CORS settings by URL pattern. If both are specified, they are combined by using the
<code>combine</code> method on <code>CorsConfiguration</code>.</p>
</div>
</div>
<div class="sect3">
<h4 id="webflux-websocket-client">3.2.7. Client</h4>
<div class="paragraph">
<p>Spring WebFlux provides a <code>WebSocketClient</code> abstraction with implementations for
Reactor Netty, Tomcat, Jetty, Undertow, and standard Java (that is, JSR-356).</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
The Tomcat client is effectively an extension of the standard Java one with some extra
functionality in the <code>WebSocketSession</code> handling to take advantage of the Tomcat-specific
API to suspend receiving messages for back pressure.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To start a WebSocket session, you can create an instance of the client and use its <code>execute</code>
methods:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">WebSocketClient client = new ReactorNettyWebSocketClient();

URI url = new URI("ws://localhost:8080/path");
client.execute(url, session -&gt;
        session.receive()
                .doOnNext(System.out::println)
                .then());</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val client = ReactorNettyWebSocketClient()

        val url = URI("ws://localhost:8080/path")
        client.execute(url) { session -&gt;
            session.receive()
                    .doOnNext(::println)
            .then()
        }</code></pre>
</div>
</div>
<div class="paragraph">
<p>Some clients, such as Jetty, implement <code>Lifecycle</code> and need to be stopped and started
before you can use them. All clients have constructor options related to configuration
of the underlying WebSocket client.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="webflux-test">4. Testing</h2>
<div class="sectionbody">
<div class="paragraph">
<p><span class="small"><a href="web.html#testing">Same in Spring MVC</a></span></p>
</div>
<div class="paragraph">
<p>The <code>spring-test</code> module provides mock implementations of <code>ServerHttpRequest</code>,
<code>ServerHttpResponse</code>, and <code>ServerWebExchange</code>.
See <a href="testing.html#mock-objects-web-reactive">Spring Web Reactive</a> for a
discussion of mock objects.</p>
</div>
<div class="paragraph">
<p><a href="testing.html#webtestclient"><code>WebTestClient</code></a> builds on these mock request and
response objects to provide support for testing WebFlux applications without an HTTP
server. You can use the <code>WebTestClient</code> for end-to-end integration tests, too.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="rsocket">5. RSocket</h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section describes Spring Framework&#8217;s support for the RSocket protocol.</p>
</div>
<div class="sect2">
<h3 id="rsocket-overview">5.1. Overview</h3>
<div class="paragraph">
<p>RSocket is an application protocol for multiplexed, duplex communication over TCP,
WebSocket, and other byte stream transports, using one of the following interaction
models:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>Request-Response</code>&#8201;&#8212;&#8201;send one message and receive one back.</p>
</li>
<li>
<p><code>Request-Stream</code>&#8201;&#8212;&#8201;send one message and receive a stream of messages back.</p>
</li>
<li>
<p><code>Channel</code>&#8201;&#8212;&#8201;send streams of messages in both directions.</p>
</li>
<li>
<p><code>Fire-and-Forget</code>&#8201;&#8212;&#8201;send a one-way message.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>Once the initial connection is made, the "client" vs "server" distinction is lost as
both sides become symmetrical and each side can initiate one of the above interactions.
This is why in the protocol calls the participating sides "requester" and "responder"
while the above interactions are called "request streams" or simply "requests".</p>
</div>
<div class="paragraph">
<p>These are the key features and benefits of the RSocket protocol:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://www.reactive-streams.org/">Reactive Streams</a> semantics across network boundary&#8201;&#8212;&#8201;for streaming requests such as <code>Request-Stream</code> and <code>Channel</code>, back pressure signals
travel between requester and responder, allowing a requester to slow down a responder at
the source, hence reducing reliance on network layer congestion control, and the need
for buffering at the network level or at any level.</p>
</li>
<li>
<p>Request throttling&#8201;&#8212;&#8201;this feature is named "Leasing" after the <code>LEASE</code> frame that
can be sent from each end to limit the total number of requests allowed by other end
for a given time. Leases are renewed periodically.</p>
</li>
<li>
<p>Session resumption&#8201;&#8212;&#8201;this is designed for loss of connectivity and requires some state
to be maintained. The state management is transparent for applications, and works well
in combination with back pressure which can stop a producer when possible and reduce
the amount of state required.</p>
</li>
<li>
<p>Fragmentation and re-assembly of large messages.</p>
</li>
<li>
<p>Keepalive (heartbeats).</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>RSocket has <a href="https://github.com/rsocket">implementations</a> in multiple languages. The
<a href="https://github.com/rsocket/rsocket-java">Java library</a> is built on <a href="https://projectreactor.io/">Project Reactor</a>,
and <a href="https://github.com/reactor/reactor-netty">Reactor Netty</a> for the transport. That means
signals from Reactive Streams Publishers in your application propagate transparently
through RSocket across the network.</p>
</div>
<div class="sect3">
<h4 id="rsocket-protocol">5.1.1. The Protocol</h4>
<div class="paragraph">
<p>One of the benefits of RSocket is that it has well defined behavior on the wire and an
easy to read <a href="https://rsocket.io/docs/Protocol">specification</a> along with some protocol
<a href="https://github.com/rsocket/rsocket/tree/master/Extensions">extensions</a>. Therefore it is
a good idea to read the spec, independent of language implementations and higher level
framework APIs. This section provides a succinct overview to establish some context.</p>
</div>
<div class="paragraph">
<p><strong>Connecting</strong></p>
</div>
<div class="paragraph">
<p>Initially a client connects to a server via some low level streaming transport such
as TCP or WebSocket and sends a <code>SETUP</code> frame to the server to set parameters for the
connection.</p>
</div>
<div class="paragraph">
<p>The server may reject the <code>SETUP</code> frame, but generally after it is sent (for the client)
and received (for the server), both sides can begin to make requests, unless <code>SETUP</code>
indicates use of leasing semantics to limit the number of requests, in which case
both sides must wait for a <code>LEASE</code> frame from the other end to permit making requests.</p>
</div>
<div class="paragraph">
<p><strong>Making Requests</strong></p>
</div>
<div class="paragraph">
<p>Once a connection is established, both sides may initiate a request through one of the
frames <code>REQUEST_RESPONSE</code>, <code>REQUEST_STREAM</code>, <code>REQUEST_CHANNEL</code>, or <code>REQUEST_FNF</code>. Each of
those frames carries one message from the requester to the responder.</p>
</div>
<div class="paragraph">
<p>The responder may then return <code>PAYLOAD</code> frames with response messages, and in the case
of <code>REQUEST_CHANNEL</code> the requester may also send <code>PAYLOAD</code> frames with more request
messages.</p>
</div>
<div class="paragraph">
<p>When a request involves a stream of messages such as <code>Request-Stream</code> and <code>Channel</code>,
the responder must respect demand signals from the requester. Demand is expressed as a
number of messages. Initial demand is specified in <code>REQUEST_STREAM</code> and
<code>REQUEST_CHANNEL</code> frames. Subsequent demand is signaled via <code>REQUEST_N</code> frames.</p>
</div>
<div class="paragraph">
<p>Each side may also send metadata notifications, via the <code>METADATA_PUSH</code> frame, that do not
pertain to any individual request but rather to the connection as a whole.</p>
</div>
<div class="paragraph">
<p><strong>Message Format</strong></p>
</div>
<div class="paragraph">
<p>RSocket messages contain data and metadata. Metadata can be used to send a route, a
security token, etc. Data and metadata can be formatted differently. Mime types for each
are declared in the <code>SETUP</code> frame and apply to all requests on a given connection.</p>
</div>
<div class="paragraph">
<p>While all messages can have metadata, typically metadata such as a route are per-request
and therefore only included in the first message on a request, i.e. with one of the frames
<code>REQUEST_RESPONSE</code>, <code>REQUEST_STREAM</code>, <code>REQUEST_CHANNEL</code>, or <code>REQUEST_FNF</code>.</p>
</div>
<div class="paragraph">
<p>Protocol extensions define common metadata formats for use in applications:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/rsocket/rsocket/blob/master/Extensions/CompositeMetadata.md">Composite Metadata</a>-- multiple,
independently formatted metadata entries.</p>
</li>
<li>
<p><a href="https://github.com/rsocket/rsocket/blob/master/Extensions/Routing.md">Routing</a>&#8201;&#8212;&#8201;the route for a request.</p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="rsocket-java">5.1.2. Java Implementation</h4>
<div class="paragraph">
<p>The <a href="https://github.com/rsocket/rsocket-java">Java implementation</a> for RSocket is built on
<a href="https://projectreactor.io/">Project Reactor</a>. The transports for  TCP and WebSocket are
built on <a href="https://github.com/reactor/reactor-netty">Reactor Netty</a>. As a Reactive Streams
library, Reactor simplifies the job of implementing the protocol. For applications it is
a natural fit to use <code>Flux</code> and <code>Mono</code> with declarative operators and transparent back
pressure support.</p>
</div>
<div class="paragraph">
<p>The API in RSocket Java is intentionally minimal and basic. It focuses on protocol
features and leaves the application programming model (e.g. RPC codegen vs other) as a
higher level, independent concern.</p>
</div>
<div class="paragraph">
<p>The main contract
<a href="https://github.com/rsocket/rsocket-java/blob/master/rsocket-core/src/main/java/io/rsocket/RSocket.java">io.rsocket.RSocket</a>
models the four request interaction types with <code>Mono</code> representing a promise for a
single message, <code>Flux</code> a stream of messages, and <code>io.rsocket.Payload</code> the actual
message with access to data and metadata as byte buffers. The <code>RSocket</code> contract is used
symmetrically. For requesting, the application is given an <code>RSocket</code> to perform
requests with. For responding, the application implements <code>RSocket</code> to handle requests.</p>
</div>
<div class="paragraph">
<p>This is not meant to be a thorough introduction. For the most part, Spring applications
will not have to use its API directly. However it may be important to see or experiment
with RSocket independent of Spring. The RSocket Java repository contains a number of
<a href="https://github.com/rsocket/rsocket-java/tree/master/rsocket-examples">sample apps</a> that
demonstrate its API and protocol features.</p>
</div>
</div>
<div class="sect3">
<h4 id="rsocket-spring">5.1.3. Spring Support</h4>
<div class="paragraph">
<p>The <code>spring-messaging</code> module contains the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="#rsocket-requester">RSocketRequester</a>&#8201;&#8212;&#8201;fluent API to make requests through an <code>io.rsocket.RSocket</code>
with data and metadata encoding/decoding.</p>
</li>
<li>
<p><a href="#rsocket-annot-responders">Annotated Responders</a>&#8201;&#8212;&#8201;<code>@MessageMapping</code> annotated handler methods for
responding.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The <code>spring-web</code> module contains <code>Encoder</code> and <code>Decoder</code> implementations such as Jackson
CBOR/JSON, and Protobuf that RSocket applications will likely need. It also contains the
<code>PathPatternParser</code> that can be plugged in for efficient route matching.</p>
</div>
<div class="paragraph">
<p>Spring Boot 2.2 supports standing up an RSocket server over TCP or WebSocket, including
the option to expose RSocket over WebSocket in a WebFlux server. There is also client
support and auto-configuration for an <code>RSocketRequester.Builder</code> and <code>RSocketStrategies</code>.
See the
<a href="https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-rsocket">RSocket section</a>
in the Spring Boot reference for more details.</p>
</div>
<div class="paragraph">
<p>Spring Security 5.2 provides RSocket support.</p>
</div>
<div class="paragraph">
<p>Spring Integration 5.2 provides inbound and outbound gateways to interact with RSocket
clients and servers. See the Spring Integration Reference Manual for more details.</p>
</div>
<div class="paragraph">
<p>Spring Cloud Gateway supports RSocket connections.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="rsocket-requester">5.2. RSocketRequester</h3>
<div class="paragraph">
<p><code>RSocketRequester</code> provides a fluent API to perform RSocket requests, accepting and
returning objects for data and metadata instead of low level data buffers. It can be used
symmetrically, to make requests from clients and to make requests from servers.</p>
</div>
<div class="sect3">
<h4 id="rsocket-requester-client">5.2.1. Client Requester</h4>
<div class="paragraph">
<p>To obtain an <code>RSocketRequester</code> on the client side is to connect to a server which involves
sending an RSocket <code>SETUP</code> frame with connection settings. <code>RSocketRequester</code> provides a
builder that helps to prepare an <code>io.rsocket.core.RSocketConnector</code> including connection
settings for the <code>SETUP</code> frame.</p>
</div>
<div class="paragraph">
<p>This is the most basic way to connect with default settings:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RSocketRequester requester = RSocketRequester.builder().tcp("localhost", 7000);

URI url = URI.create("https://example.org:8080/rsocket");
RSocketRequester requester = RSocketRequester.builder().webSocket(url);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val requester = RSocketRequester.builder().tcp("localhost", 7000)

URI url = URI.create("https://example.org:8080/rsocket");
val requester = RSocketRequester.builder().webSocket(url)</code></pre>
</div>
</div>
<div class="paragraph">
<p>The above does not connect immediately. When requests are made, a shared connection is
established transparently and used.</p>
</div>
<div class="sect4">
<h5 id="rsocket-requester-client-setup">Connection Setup</h5>
<div class="paragraph">
<p><code>RSocketRequester.Builder</code> provides the following to customize the initial <code>SETUP</code> frame:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>dataMimeType(MimeType)</code>&#8201;&#8212;&#8201;set the mime type for data on the connection.</p>
</li>
<li>
<p><code>metadataMimeType(MimeType)</code>&#8201;&#8212;&#8201;set the mime type for metadata on the connection.</p>
</li>
<li>
<p><code>setupData(Object)</code>&#8201;&#8212;&#8201;data to include in the <code>SETUP</code>.</p>
</li>
<li>
<p><code>setupRoute(String, Object&#8230;&#8203;)</code>&#8201;&#8212;&#8201;route in the metadata to include in the <code>SETUP</code>.</p>
</li>
<li>
<p><code>setupMetadata(Object, MimeType)</code>&#8201;&#8212;&#8201;other metadata to include in the <code>SETUP</code>.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For data, the default mime type is derived from the first configured <code>Decoder</code>. For
metadata, the default mime type is
<a href="https://github.com/rsocket/rsocket/blob/master/Extensions/CompositeMetadata.md">composite metadata</a> which allows multiple
metadata value and mime type pairs per request. Typically both don&#8217;t need to be changed.</p>
</div>
<div class="paragraph">
<p>Data and metadata in the <code>SETUP</code> frame is optional. On the server side,
<a href="#rsocket-annot-connectmapping">@ConnectMapping</a> methods can be used to handle the start of a
connection and the content of the <code>SETUP</code> frame. Metadata may be used for connection
level security.</p>
</div>
</div>
<div class="sect4">
<h5 id="rsocket-requester-client-strategies">Strategies</h5>
<div class="paragraph">
<p><code>RSocketRequester.Builder</code> accepts <code>RSocketStrategies</code> to configure the requester.
You&#8217;ll need to use this to provide encoders and decoders for (de)-serialization of data and
metadata values. By default only the basic codecs from <code>spring-core</code> for <code>String</code>,
<code>byte[]</code>, and <code>ByteBuffer</code> are registered. Adding <code>spring-web</code> provides access to more that
can be registered as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RSocketStrategies strategies = RSocketStrategies.builder()
    .encoders(encoders -&gt; encoders.add(new Jackson2CborEncoder()))
    .decoders(decoders -&gt; decoders.add(new Jackson2CborDecoder()))
    .build();

RSocketRequester requester = RSocketRequester.builder()
    .rsocketStrategies(strategies)
    .tcp("localhost", 7000);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val strategies = RSocketStrategies.builder()
        .encoders { it.add(Jackson2CborEncoder()) }
        .decoders { it.add(Jackson2CborDecoder()) }
        .build()

val requester = RSocketRequester.builder()
        .rsocketStrategies(strategies)
        .tcp("localhost", 7000)</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>RSocketStrategies</code> is designed for re-use. In some scenarios, e.g. client and server in
the same application, it may be preferable to declare it in Spring configuration.</p>
</div>
</div>
<div class="sect4">
<h5 id="rsocket-requester-client-responder">Client Responders</h5>
<div class="paragraph">
<p><code>RSocketRequester.Builder</code> can be used to configure responders to requests from the
server.</p>
</div>
<div class="paragraph">
<p>You can use annotated handlers for client-side responding based on the same
infrastructure that&#8217;s used on a server, but registered programmatically as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RSocketStrategies strategies = RSocketStrategies.builder()
    .routeMatcher(new PathPatternRouteMatcher())  <i class="conum" data-value="1"></i><b>(1)</b>
    .build();

SocketAcceptor responder =
    RSocketMessageHandler.responder(strategies, new ClientHandler()); <i class="conum" data-value="2"></i><b>(2)</b>

RSocketRequester requester = RSocketRequester.builder()
    .rsocketConnector(connector -&gt; connector.acceptor(responder)) <i class="conum" data-value="3"></i><b>(3)</b>
    .tcp("localhost", 7000);</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Use <code>PathPatternRouteMatcher</code>, if <code>spring-web</code> is present, for efficient
route matching.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Create a responder from a class with <code>@MessageMaping</code> and/or <code>@ConnectMapping</code> methods.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Register the responder.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val strategies = RSocketStrategies.builder()
        .routeMatcher(PathPatternRouteMatcher())  <i class="conum" data-value="1"></i><b>(1)</b>
        .build()

val responder =
    RSocketMessageHandler.responder(strategies, new ClientHandler()); <i class="conum" data-value="2"></i><b>(2)</b>

val requester = RSocketRequester.builder()
        .rsocketConnector { it.acceptor(responder) } <i class="conum" data-value="3"></i><b>(3)</b>
        .tcp("localhost", 7000)</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Use <code>PathPatternRouteMatcher</code>, if <code>spring-web</code> is present, for efficient
route matching.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Create a responder from a class with <code>@MessageMaping</code> and/or <code>@ConnectMapping</code> methods.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Register the responder.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Note the above is only a shortcut designed for programmatic registration of client
responders. For alternative scenarios, where client responders are in Spring configuration,
you can still declare <code>RSocketMessageHandler</code> as a Spring bean and then apply as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">ApplicationContext context = ... ;
RSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);

RSocketRequester requester = RSocketRequester.builder()
    .rsocketConnector(connector -&gt; connector.acceptor(handler.responder()))
    .tcp("localhost", 7000);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.beans.factory.getBean

val context: ApplicationContext = ...
val handler = context.getBean&lt;RSocketMessageHandler&gt;()

val requester = RSocketRequester.builder()
        .rsocketConnector { it.acceptor(handler.responder()) }
        .tcp("localhost", 7000)</code></pre>
</div>
</div>
<div class="paragraph">
<p>For the above you may also need to use <code>setHandlerPredicate</code> in <code>RSocketMessageHandler</code> to
switch to a different strategy for detecting client responders, e.g. based on a custom
annotation such as <code>@RSocketClientResponder</code> vs the default <code>@Controller</code>. This
is necessary in scenarios with client and server, or multiple clients in the same
application.</p>
</div>
<div class="paragraph">
<p>See also <a href="#rsocket-annot-responders">Annotated Responders</a>, for more on the programming model.</p>
</div>
</div>
<div class="sect4">
<h5 id="rsocket-requester-client-advanced">Advanced</h5>
<div class="paragraph">
<p><code>RSocketRequesterBuilder</code> provides a callback to expose the underlying
<code>io.rsocket.core.RSocketConnector</code> for further configuration options for keepalive
intervals, session resumption, interceptors, and more. You can configure options
at that level as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RSocketRequester requester = RSocketRequester.builder()
    .rsocketConnector(connector -&gt; {
        // ...
    })
    .tcp("localhost", 7000);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val requester = RSocketRequester.builder()
        .rsocketConnector {
            //...
        }
        .tcp("localhost", 7000)</code></pre>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="rsocket-requester-server">5.2.2. Server Requester</h4>
<div class="paragraph">
<p>To make requests from a server to connected clients is a matter of obtaining the
requester for the connected client from the server.</p>
</div>
<div class="paragraph">
<p>In <a href="#rsocket-annot-responders">Annotated Responders</a>, <code>@ConnectMapping</code> and <code>@MessageMapping</code> methods support an
<code>RSocketRequester</code> argument. Use it to access the requester for the connection. Keep in
mind that <code>@ConnectMapping</code> methods are essentially handlers of the <code>SETUP</code> frame which
must be handled before requests can begin. Therefore, requests at the very start must be
decoupled from handling. For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@ConnectMapping
Mono&lt;Void&gt; handle(RSocketRequester requester) {
    requester.route("status").data("5")
        .retrieveFlux(StatusReport.class)
        .subscribe(bar -&gt; { <i class="conum" data-value="1"></i><b>(1)</b>
            // ...
        });
    return ... <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Start the request asynchronously, independent from handling.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Perform handling and return completion <code>Mono&lt;Void&gt;</code>.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@ConnectMapping
suspend fun handle(requester: RSocketRequester) {
    GlobalScope.launch {
        requester.route("status").data("5").retrieveFlow&lt;StatusReport&gt;().collect { <i class="conum" data-value="1"></i><b>(1)</b>
            // ...
        }
    }
    /// ... <i class="conum" data-value="2"></i><b>(2)</b>
}</code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Start the request asynchronously, independent from handling.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Perform handling in the suspending function.</td>
</tr>
</table>
</div>
</div>
<div class="sect3">
<h4 id="rsocket-requester-requests">5.2.3. Requests</h4>
<div class="paragraph">
<p>Once you have a <a href="#rsocket-requester-client">client</a> or
<a href="#rsocket-requester-server">server</a> requester, you can make requests as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">ViewBox viewBox = ... ;

Flux&lt;AirportLocation&gt; locations = requester.route("locate.radars.within") <i class="conum" data-value="1"></i><b>(1)</b>
        .data(viewBox) <i class="conum" data-value="2"></i><b>(2)</b>
        .retrieveFlux(AirportLocation.class); <i class="conum" data-value="3"></i><b>(3)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Specify a route to include in the metadata of the request message.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Provide data for the request message.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Declare the expected response.</td>
</tr>
</table>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">val viewBox: ViewBox = ...

val locations = requester.route("locate.radars.within") <i class="conum" data-value="1"></i><b>(1)</b>
        .data(viewBox) <i class="conum" data-value="2"></i><b>(2)</b>
        .retrieveFlow&lt;AirportLocation&gt;() <i class="conum" data-value="3"></i><b>(3)</b></code></pre>
</div>
</div>
<div class="colist arabic">
<table>
<tr>
<td><i class="conum" data-value="1"></i><b>1</b></td>
<td>Specify a route to include in the metadata of the request message.</td>
</tr>
<tr>
<td><i class="conum" data-value="2"></i><b>2</b></td>
<td>Provide data for the request message.</td>
</tr>
<tr>
<td><i class="conum" data-value="3"></i><b>3</b></td>
<td>Declare the expected response.</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The interaction type is determined implicitly from the cardinality of the input and
output. The above example is a <code>Request-Stream</code> because one value is sent and a stream
of values is received. For the most part you don&#8217;t need to think about this as long as the
choice of input and output matches an RSocket interaction type and the types of input and
output expected by the responder. The only example of an invalid combination is many-to-one.</p>
</div>
<div class="paragraph">
<p>The <code>data(Object)</code> method also accepts any Reactive Streams <code>Publisher</code>, including
<code>Flux</code> and <code>Mono</code>, as well as any other producer of value(s) that is registered in the
<code>ReactiveAdapterRegistry</code>. For a multi-value <code>Publisher</code> such as <code>Flux</code> which produces the
same types of values, consider using one of the overloaded <code>data</code> methods to avoid having
type checks and <code>Encoder</code> lookup on every element:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">data(Object producer, Class&lt;?&gt; elementClass);
data(Object producer, ParameterizedTypeReference&lt;?&gt; elementTypeRef);</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>data(Object)</code> step is optional. Skip it for requests that don&#8217;t send data:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">Mono&lt;AirportLocation&gt; location = requester.route("find.radar.EWR"))
    .retrieveMono(AirportLocation.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.messaging.rsocket.retrieveAndAwait

val location = requester.route("find.radar.EWR")
    .retrieveAndAwait&lt;AirportLocation&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>Extra metadata values can be added if using
<a href="https://github.com/rsocket/rsocket/blob/master/Extensions/CompositeMetadata.md">composite metadata</a> (the default) and if the
values are supported by a registered <code>Encoder</code>. For example:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">String securityToken = ... ;
ViewBox viewBox = ... ;
MimeType mimeType = MimeType.valueOf("message/x.rsocket.authentication.bearer.v0");

Flux&lt;AirportLocation&gt; locations = requester.route("locate.radars.within")
        .metadata(securityToken, mimeType)
        .data(viewBox)
        .retrieveFlux(AirportLocation.class);</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.messaging.rsocket.retrieveFlow

val requester: RSocketRequester = ...

val securityToken: String = ...
val viewBox: ViewBox = ...
val mimeType = MimeType.valueOf("message/x.rsocket.authentication.bearer.v0")

val locations = requester.route("locate.radars.within")
        .metadata(securityToken, mimeType)
        .data(viewBox)
        .retrieveFlow&lt;AirportLocation&gt;()</code></pre>
</div>
</div>
<div class="paragraph">
<p>For <code>Fire-and-Forget</code> use the <code>send()</code> method that returns <code>Mono&lt;Void&gt;</code>. Note that the <code>Mono</code>
indicates only that the message was successfully sent, and not that it was handled.</p>
</div>
<div class="paragraph">
<p>For <code>Metadata-Push</code> use the <code>sendMetadata()</code> method with a <code>Mono&lt;Void&gt;</code> return value.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="rsocket-annot-responders">5.3. Annotated Responders</h3>
<div class="paragraph">
<p>RSocket responders can be implemented as <code>@MessageMapping</code> and <code>@ConnectMapping</code> methods.
<code>@MessageMapping</code> methods handle individual requests while <code>@ConnectMapping</code> methods handle
connection-level events (setup and metadata push). Annotated responders are supported
symmetrically, for responding from the server side and for responding from the client side.</p>
</div>
<div class="sect3">
<h4 id="rsocket-annot-responders-server">5.3.1. Server Responders</h4>
<div class="paragraph">
<p>To use annotated responders on the server side, add <code>RSocketMessageHandler</code> to your Spring
configuration to detect <code>@Controller</code> beans with <code>@MessageMapping</code> and <code>@ConnectMapping</code>
methods:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
static class ServerConfig {

    @Bean
    public RSocketMessageHandler rsocketMessageHandler() {
        RSocketMessageHandler handler = new RSocketMessageHandler();
        handler.routeMatcher(new PathPatternRouteMatcher());
        return handler;
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class ServerConfig {

    @Bean
    fun rsocketMessageHandler() = RSocketMessageHandler().apply {
        routeMatcher = PathPatternRouteMatcher()
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>Then start an RSocket server through the Java RSocket API and plug the
<code>RSocketMessageHandler</code> for the responder as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">ApplicationContext context = ... ;
RSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);

CloseableChannel server =
    RSocketServer.create(handler.responder())
        .bind(TcpServerTransport.create("localhost", 7000))
        .block();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.beans.factory.getBean

val context: ApplicationContext = ...
val handler = context.getBean&lt;RSocketMessageHandler&gt;()

val server = RSocketServer.create(handler.responder())
        .bind(TcpServerTransport.create("localhost", 7000))
        .awaitSingle()</code></pre>
</div>
</div>
<div class="paragraph">
<p><code>RSocketMessageHandler</code> supports
<a href="https://github.com/rsocket/rsocket/blob/master/Extensions/CompositeMetadata.md">composite</a> and
<a href="https://github.com/rsocket/rsocket/blob/master/Extensions/Routing.md">routing</a> metadata by default. You can set its
<a href="#rsocket-metadata-extractor">MetadataExtractor</a> if you need to switch to a
different mime type or register additional metadata mime types.</p>
</div>
<div class="paragraph">
<p>You&#8217;ll need to set the <code>Encoder</code> and <code>Decoder</code> instances required for metadata and data
formats to support. You&#8217;ll likely need the <code>spring-web</code> module for codec implementations.</p>
</div>
<div class="paragraph">
<p>By default <code>SimpleRouteMatcher</code> is used for matching routes via <code>AntPathMatcher</code>.
We recommend plugging in the <code>PathPatternRouteMatcher</code> from <code>spring-web</code> for
efficient route matching. RSocket routes can be hierarchical but are not URL paths.
Both route matchers are configured to use "." as separator by default and there is no URL
decoding as with HTTP URLs.</p>
</div>
<div class="paragraph">
<p><code>RSocketMessageHandler</code> can be configured via <code>RSocketStrategies</code> which may be useful if
you need to share configuration between a client and a server in the same process:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Configuration
static class ServerConfig {

    @Bean
    public RSocketMessageHandler rsocketMessageHandler() {
        RSocketMessageHandler handler = new RSocketMessageHandler();
        handler.setRSocketStrategies(rsocketStrategies());
        return handler;
    }

    @Bean
    public RSocketStrategies rsocketStrategies() {
        return RSocketStrategies.builder()
            .encoders(encoders -&gt; encoders.add(new Jackson2CborEncoder()))
            .decoders(decoders -&gt; decoders.add(new Jackson2CborDecoder()))
            .routeMatcher(new PathPatternRouteMatcher())
            .build();
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Configuration
class ServerConfig {

    @Bean
    fun rsocketMessageHandler() = RSocketMessageHandler().apply {
        rSocketStrategies = rsocketStrategies()
    }

    @Bean
    fun rsocketStrategies() = RSocketStrategies.builder()
            .encoders { it.add(Jackson2CborEncoder()) }
            .decoders { it.add(Jackson2CborDecoder()) }
            .routeMatcher(PathPatternRouteMatcher())
            .build()
}</code></pre>
</div>
</div>
</div>
<div class="sect3">
<h4 id="rsocket-annot-responders-client">5.3.2. Client Responders</h4>
<div class="paragraph">
<p>Annotated responders on the client side need to be configured in the
<code>RSocketRequester.Builder</code>. For details, see
<a href="#rsocket-requester-client-responder">Client Responders</a>.</p>
</div>
</div>
<div class="sect3">
<h4 id="rsocket-annot-messagemapping">5.3.3. @MessageMapping</h4>
<div class="paragraph">
<p>Once <a href="#rsocket-annot-responders-server">server</a> or
<a href="#rsocket-annot-responders-client">client</a> responder configuration is in place,
<code>@MessageMapping</code> methods can be used as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">@Controller
public class RadarsController {

    @MessageMapping("locate.radars.within")
    public Flux&lt;AirportLocation&gt; radars(MapRequest request) {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">@Controller
class RadarsController {

    @MessageMapping("locate.radars.within")
    fun radars(request: MapRequest): Flow&lt;AirportLocation&gt; {
        // ...
    }
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The above <code>@MessageMapping</code> method responds to a Request-Stream interaction having the
route "locate.radars.within". It supports a flexible method signature with the option to
use the following method arguments:</p>
</div>
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Method Argument</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@Payload</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The payload of the request. This can be a concrete value of asynchronous types like
  <code>Mono</code> or <code>Flux</code>.</p>
<p class="tableblock">  <strong>Note:</strong> Use of the annotation is optional. A method argument that is not a simple type
  and is not any of the other supported arguments, is assumed to be the expected payload.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>RSocketRequester</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Requester for making requests to the remote end.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@DestinationVariable</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Value extracted from the route based on variables in the mapping pattern, e.g.
  <code>@MessageMapping("find.radar.{id}")</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@Header</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Metadata value registered for extraction as described in <a href="#rsocket-metadata-extractor">MetadataExtractor</a>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>@Headers Map&lt;String, Object&gt;</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">All metadata values registered for extraction as described in <a href="#rsocket-metadata-extractor">MetadataExtractor</a>.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The return value is expected to be one or more Objects to be serialized as response
payloads. That can be asynchronous types like <code>Mono</code> or <code>Flux</code>, a concrete value, or
either <code>void</code> or a no-value asynchronous type such as <code>Mono&lt;Void&gt;</code>.</p>
</div>
<div class="paragraph">
<p>The RSocket interaction type that an <code>@MessageMapping</code> method supports is determined from
the cardinality of the input (i.e. <code>@Payload</code> argument) and of the output, where
cardinality means the following:</p>
</div>
<table class="tableblock frame-all grid-all fit-content">
<colgroup>
<col>
<col>
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Cardinality</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Either an explicit value, or a single-value asynchronous type such as <code>Mono&lt;T&gt;</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Many</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A multi-value asynchronous type such as <code>Flux&lt;T&gt;</code>.</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">For input this means the method does not have an <code>@Payload</code> argument.</p>
<p class="tableblock">  For output this is <code>void</code> or a no-value asynchronous type such as <code>Mono&lt;Void&gt;</code>.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>The table below shows all input and output cardinality combinations and the corresponding
interaction type(s):</p>
</div>
<table class="tableblock frame-all grid-all fit-content">
<colgroup>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Input Cardinality</th>
<th class="tableblock halign-left valign-top">Output Cardinality</th>
<th class="tableblock halign-left valign-top">Interaction Types</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">0, 1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Fire-and-Forget, Request-Response</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">0, 1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Request-Response</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">0, 1</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Many</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Request-Stream</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Many</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">0, 1, Many</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Request-Channel</p></td>
</tr>
</tbody>
</table>
</div>
<div class="sect3">
<h4 id="rsocket-annot-connectmapping">5.3.4. @ConnectMapping</h4>
<div class="paragraph">
<p><code>@ConnectMapping</code> handles the <code>SETUP</code> frame at the start of an RSocket connection, and
any subsequent metadata push notifications through the <code>METADATA_PUSH</code> frame, i.e.
<code>metadataPush(Payload)</code> in <code>io.rsocket.RSocket</code>.</p>
</div>
<div class="paragraph">
<p><code>@ConnectMapping</code> methods support the same arguments as
<a href="#rsocket-annot-messagemapping">@MessageMapping</a> but based on metadata and data from the <code>SETUP</code> and
<code>METADATA_PUSH</code> frames. <code>@ConnectMapping</code> can have a pattern to narrow handling to
specific connections that have a route in the metadata, or if no patterns are declared
then all connections match.</p>
</div>
<div class="paragraph">
<p><code>@ConnectMapping</code> methods cannot return data and must be declared with <code>void</code> or
<code>Mono&lt;Void&gt;</code> as the return value. If handling returns an error for a new
connection then the connection is rejected. Handling must not be held up to make
requests to the <code>RSocketRequester</code> for the connection. See
<a href="#rsocket-requester-server">Server Requester</a> for details.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="rsocket-metadata-extractor">5.4. MetadataExtractor</h3>
<div class="paragraph">
<p>Responders must interpret metadata.
<a href="https://github.com/rsocket/rsocket/blob/master/Extensions/CompositeMetadata.md">Composite metadata</a> allows independently
formatted metadata values (e.g. for routing, security, tracing) each with its own mime
type. Applications need a way to configure metadata mime types to support, and a way
to access extracted values.</p>
</div>
<div class="paragraph">
<p><code>MetadataExtractor</code> is a contract to take serialized metadata and return decoded
name-value pairs that can then be accessed like headers by name, for example via <code>@Header</code>
in annotated handler methods.</p>
</div>
<div class="paragraph">
<p><code>DefaultMetadataExtractor</code> can be given <code>Decoder</code> instances to decode metadata. Out of
the box it has built-in support for
<a href="https://github.com/rsocket/rsocket/blob/master/Extensions/Routing.md">"message/x.rsocket.routing.v0"</a> which it decodes to
<code>String</code> and saves under the "route" key. For any other mime type you&#8217;ll need to provide
a <code>Decoder</code> and register the mime type as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">DefaultMetadataExtractor extractor = new DefaultMetadataExtractor(metadataDecoders);
extractor.metadataToExtract(fooMimeType, Foo.class, "foo");</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.messaging.rsocket.metadataToExtract

val extractor = DefaultMetadataExtractor(metadataDecoders)
extractor.metadataToExtract&lt;Foo&gt;(fooMimeType, "foo")</code></pre>
</div>
</div>
<div class="paragraph">
<p>Composite metadata works well to combine independent metadata values. However the
requester might not support composite metadata, or may choose not to use it. For this,
<code>DefaultMetadataExtractor</code> may needs custom logic to map the decoded value to the output
map. Here is an example where JSON is used for metadata:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">DefaultMetadataExtractor extractor = new DefaultMetadataExtractor(metadataDecoders);
extractor.metadataToExtract(
    MimeType.valueOf("application/vnd.myapp.metadata+json"),
    new ParameterizedTypeReference&lt;Map&lt;String,String&gt;&gt;() {},
    (jsonMap, outputMap) -&gt; {
        outputMap.putAll(jsonMap);
    });</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.messaging.rsocket.metadataToExtract

val extractor = DefaultMetadataExtractor(metadataDecoders)
extractor.metadataToExtract&lt;Map&lt;String, String&gt;&gt;(MimeType.valueOf("application/vnd.myapp.metadata+json")) { jsonMap, outputMap -&gt;
    outputMap.putAll(jsonMap)
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>When configuring <code>MetadataExtractor</code> through <code>RSocketStrategies</code>, you can let
<code>RSocketStrategies.Builder</code> create the extractor with the configured decoders, and
simply use a callback to customize registrations as follows:</p>
</div>
<div class="listingblock primary">
<div class="title">Java</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="java">RSocketStrategies strategies = RSocketStrategies.builder()
    .metadataExtractorRegistry(registry -&gt; {
        registry.metadataToExtract(fooMimeType, Foo.class, "foo");
        // ...
    })
    .build();</code></pre>
</div>
</div>
<div class="listingblock secondary">
<div class="title">Kotlin</div>
<div class="content">
<pre class="prettyprint highlight"><code data-lang="kotlin">import org.springframework.messaging.rsocket.metadataToExtract

val strategies = RSocketStrategies.builder()
        .metadataExtractorRegistry { registry: MetadataExtractorRegistry -&gt;
            registry.metadataToExtract&lt;Foo&gt;(fooMimeType, "foo")
            // ...
        }
        .build()</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="webflux-reactive-libraries">6. Reactive Libraries</h2>
<div class="sectionbody">
<div class="paragraph">
<p><code>spring-webflux</code> depends on <code>reactor-core</code> and uses it internally to compose asynchronous
logic and to provide Reactive Streams support. Generally, WebFlux APIs return <code>Flux</code> or
<code>Mono</code> (since those are used internally) and leniently accept any Reactive Streams
<code>Publisher</code> implementation as input. The use of <code>Flux</code> versus <code>Mono</code> is important, because
it helps to express cardinality&#8201;&#8212;&#8201;for example, whether a single or multiple asynchronous
values are expected, and that can be essential for making decisions (for example, when
encoding or decoding HTTP messages).</p>
</div>
<div class="paragraph">
<p>For annotated controllers, WebFlux transparently adapts to the reactive library chosen by
the application. This is done with the help of the
<a href="https://docs.spring.io/spring-framework/docs/{spring-version}/javadoc-api/org/springframework/core/ReactiveAdapterRegistry.html"><code>ReactiveAdapterRegistry</code></a>, which
provides pluggable support for reactive library and other asynchronous types. The registry
has built-in support for RxJava 2/3, RxJava 1 (via RxJava Reactive Streams bridge), and
<code>CompletableFuture</code>, but you can register others, too.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
<div class="paragraph">
<p>As of Spring Framework 5.3, support for RxJava 1 is deprecated.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For functional APIs (such as <a href="#webflux-fn">Functional Endpoints</a>, the <code>WebClient</code>, and others), the general rules
for WebFlux APIs apply&#8201;&#8212;&#8201;<code>Flux</code> and <code>Mono</code> as return values and a Reactive Streams
<code>Publisher</code> as input. When a <code>Publisher</code>, whether custom or from another reactive library,
is provided, it can be treated only as a stream with unknown semantics (0..N). If, however,
the semantics are known, you can wrap it with <code>Flux</code> or <code>Mono.from(Publisher)</code> instead
of passing the raw <code>Publisher</code>.</p>
</div>
<div class="paragraph">
<p>For example, given a <code>Publisher</code> that is not a <code>Mono</code>, the Jackson JSON message writer
expects multiple values. If the media type implies an infinite stream (for example,
<code>application/json+stream</code>), values are written and flushed individually. Otherwise,
values are buffered into a list and rendered as a JSON array.</p>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/prettify.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prettify/r298/run_prettify.min.js"></script>
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  messageStyle: "none",
  tex2jax: {
    inlineMath: [["\\(", "\\)"]],
    displayMath: [["\\[", "\\]"]],
    ignoreClass: "nostem|nolatexmath"
  },
  asciimath2jax: {
    delimiters: [["\\$", "\\$"]],
    ignoreClass: "nostem|noasciimath"
  },
  TeX: { equationNumbers: { autoNumber: "none" } }
})
MathJax.Hub.Register.StartupHook("AsciiMath Jax Ready", function () {
  MathJax.InputJax.AsciiMath.postfilterHooks.Add(function (data, node) {
    if ((node = data.script.parentNode) && (node = node.parentNode) && node.classList.contains('stemblock')) {
      data.math.root.display = "block"
    }
    return data
  })
})
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_HTMLorMML"></script>
</body>
</html>